【问题标题】:Creating a delete button for each record为每条记录创建一个删除按钮
【发布时间】:2016-11-19 23:57:24
【问题描述】:

我有一个网站,我在数据库中有一堆记录。有两个字段,Name 和 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"

我有一个页面,其中显示了所有记录,旁边有一个删除按钮。我的当前页面:

我有以下views.py(只是相关功能):

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})

相关的 DTL 部分:

{% 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 %}

除了偶尔会引发错误之外,所有这些都可以正常工作:

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'

这行是罪魁祸首:

objects[int(list(request.POST)[-1])].delete()

出于某种奇怪的原因,request.POST 仅包含 csrf_token,但不包含提交按钮。请注意,它也只是偶尔发生。

我在 stackoverflow 上搜索了一下,只发现了这个用复选框删除的帖子:Django: writing a view to delete an item with checkboxes

我该怎么做才能避免这种情况?我正在做的事情有更好的选择吗?

【问题讨论】:

  • 你想在这里做什么:int(list(request.POST)[-1])? request.POST 是键/值对的字典。尝试将其转换为列表是没有意义的。尝试根据它们在数据库中的顺序删除对象也没有任何意义 - 您需要改用它们的数据库 ID。
  • @solarissmoke 我明白了。这解释了偶尔的错误。有更好的方法吗?如果是这样,请将其发布为答案! (我会想象像[x for x in request.POST if x != 'csrfmiddlewaretoken'] 这样的索引)

标签: python django post


【解决方案1】:

我会建议完全不同的方法。

在你看来,传递对象本身:

objects = Db_test.objects.all()
return render(request, "models_test/delete.html", {"values": objects})

在您的模板中:

{% 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 %}

再次在你看来:

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()

几个通用的cmets:

  • 将[obj.name, obj.comment] 之类的列表传递给您的模板没有任何好处。只需传递对象本身。这将更容易维护。

  • 在这里根据自然数据库顺序进行更改绝对不是正确的方法 - 实际上它很危险且容易出错(例如,如果在呈现表单时将项目添加到数据库怎么办?)。您的数据库对象有一个唯一的 ID 来识别它们 - 使用它。

  • request.POST 是一个字典。将其转换为列表没有意义。如果您提供所有具有相同名称的输入列表,您可以使用getlist() 来获取它们。

【讨论】:

  • 代码运行良好。但是,还有其他方法可以保留value='X'吗?
  • 没有&lt;input&gt; 标签。您可以改用button:&lt;button type="submit" name="delete_items" value="{{ obj.pk }}"&gt;X&lt;/button&gt;
猜你喜欢
  • 1970-01-01
  • 2020-09-28
  • 1970-01-01
  • 1970-01-01
  • 2021-09-09
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多