问题
I have a website which I have a bunch of records in the database. There are two fields, Name and Comment. models.py:
class Db_test(models.Model):
name = models.CharField(max_length=50)
comment = models.CharField(max_length=200)
created = models.DateField(auto_now_add=True)
modified = models.DateField(auto_now=True)
class Meta:
db_table = "db_test"
I have a page where all the records are displayed with a delete button next to it. My current page:
I have the following views.py (just the relevant function):
def delete(request):
objects = Db_test.objects.all()
items = []
if request.method == "POST":
print(int(list(request.POST)[-1]))
objects[int(list(request.POST)[-1])].delete()
for obj in objects:
items.append([obj.name, obj.comment])
return render(request, "models_test/delete.html", {"values": items})
The relevant DTL section:
{% for i in values %}
<form method="POST">
{% csrf_token %}
<p>{{ forloop.counter }}: {{ i.0 }}<input type="submit" name={{forloop.counter0}} value="X"></p>
<p>{{ i.1 }}</p>
</form>
{% endfor %}
All this works fine except that it occasionally raises an error:
Traceback (most recent call last):
File "/home/mooncheesez/Desktop/django_projects/test_project/venv/lib/python3.4/site-packages/django/core/handlers/base.py", line 149, in get_response
response = self.process_exception_by_middleware(e, request)
File "/home/mooncheesez/Desktop/django_projects/test_project/venv/lib/python3.4/site-packages/django/core/handlers/base.py", line 147, in get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/mooncheesez/Desktop/django_projects/test_project/venv/testproject/models_test/views.py", line 32, in delete
print(int(list(request.POST)[-1]))
ValueError: invalid literal for int() with base 10: 'csrfmiddlewaretoken'
This line is the culprit:
objects[int(list(request.POST)[-1])].delete()
For some odd reason, request.POST only contains the csrf_token but not the submitted button. Note that it only happens occasionally too.
I searched around stackoverflow and I only found this post for deleting with checkboxes: Django: writing a view to delete an item with checkboxes
What do I do to avoid this? Are there better alternatives for what I am doing?
回答1:
I would suggest a different approach altogether.
In your view, pass the object itself:
objects = Db_test.objects.all()
return render(request, "models_test/delete.html", {"values": objects})
In your template:
{% for obj in object %}
<form method="POST">
{% csrf_token %}
<p>{{ forloop.counter }}: {{ obj.name }}<input type="submit" name="delete_items" value="{{ obj.pk }}"></p>
<p>{{ obj.comment }}</p>
</form>
{% endfor %}
In your view again:
if request.method == "POST":
# Fetch list of items to delete, by ID
items_to_delete = request.POST.getlist('delete_items')
# Delete those items all in one go
Db_test.objects.filter(pk__in=items_to_delete).delete()
A few general comments:
There is nothing to be gained by passing a list like
[obj.name, obj.comment]to your template. Just pass the object itself. This will be much easier to maintain.Making changes based on natural database order is definitely not the right approach here - in fact it is dangerous and error-prone (e.g, what if items were added to the database while you were rendering the form?). Your database objects have a unique ID to identify them - use that.
request.POSTis a dictionary. Converting it to a list doesn't make sense. If you supply a list of inputs all with the same name, you can use getlist() to fetch them.
来源:https://stackoverflow.com/questions/38418713/creating-a-delete-button-for-each-record