如何使用django formset动态删除对象
How to dynamically delete object using django formset
Django 说,我应该这样渲染 inline formset
:
{{ formset.management_form }}
{% for form in formset %}
{{ form.id }}
{{ form.field_1 }}
{{ form.field_2 }}
<button type="button"> delete </button>
{% endfor %}
<button type="submit"> submit </button>
好的。但是,如果我想动态删除一些 formset 对象 (form
) 怎么办?用户按下 delete
按钮 - 我从 DOM 中删除 form
,我使用 ajax 从数据库中删除与 form
相关的对象。到目前为止它工作正常。但是当用户点击 submit
- 我的 views.py 试图验证 formset:
filled_formset = OrderItemFormSet(request.POST, instance=order)
if filled_formset.is_valid():
并引发错误:
MultiValueDictKeyError at /order/cart/
"'orderitem_set-0-id'"
...\market\ordersys\views.py in show_cart
59. if filled_formset.is_valid():
我认为它发生是因为 form
对象被 django 以某种规律性显示(第一个形式得到 id = orderitem_set-0-id
,第二个 = orderitem_set-1-id
等)当我首先删除form
从 DOM 开始,规律性被打破了 - 不再有 form
和 orderitem_set-0-id
。但 is_valid()
仍在努力获得它 dict["orderitem_set-0-id"]
。
我可以使用一些黑魔法,替换显示在 DOM 中的 django 的技术信息,恢复被破坏的规律性,但是有没有更好的方法?
你能告诉我如何正确地动态删除 formset 项目吗?
我有一段时间没有得到答案,所以我没有找到比下面更好的解决方案。也许有人会觉得它有用。
好的,诀窍是 - 在模板中的 formset
中为任何 form
设置 {{form.DELETE}}
。它呈现为一个复选框(我让它不可见)并且我让 JS 使它成为 "checked" 每当用户按下 "delete" 按钮时。用户按下 "submit" 按钮后,每个标记为删除的 form
将不会在 filled_formset.is_valid()
期间由视图验证。这使您可以在后台使用 ajax 从数据库中删除对象。
The problem was that an ERROR was raised during formset validation. Caused by the form of an object, which was already deleted from database with ajax.
所以有所有组件:
views.py
def show_cart(request):
OrderItemFormSet = inlineformset_factory(Order, OrderItem, form=OrderItemForm, extra=0, can_delete=True)
order = Order.objects.get(pk=request.session['order'])
if request.method == 'GET':
formset = OrderItemFormSet(instance=order)
return render(request, 'ordersys/cart.html', {'formset': formset})
elif request.method == 'POST':
filled_formset = OrderItemFormSet(request.POST, instance=order)
if filled_formset.is_valid():
filled_formset.save()
return redirect('catalog:index')
else:
return render(request, 'ordersys/cart.html', {'formset': filled_formset})
cart.html
<form action="" method="post">
{{ formset.management_form }}
{% for form in formset %}
{{ form.id }}
{{ form.DELETE|add_class:"not_displayed" }} # custom filter
<img src="{{ form.instance.spec_prod.product.picture.url }}">
{{ form.quantity.label_tag }}
{{ form.quantity }}
{{ form.errors }}
<button type="button">Delete</button>
{% endfor %}
<button type="submit">Submit</button>
</form>
接下来,如果用户按下 'DELETE' 按钮,我的 JavaScript
1. 用 $(item).css('display', 'none');
隐藏 form
2. 使用 ItemDelCheckbox.prop('checked', true);
选中 form.DELETE
复选框
3. 发送 ajax 请求从数据库中删除项目(否则如果用户刷新页面,该项目仍在购物车中)
views.py
def delete_order_item(request): # meets the ajax request
item_id = int(request.POST['item_id'])
order = get_object_or_404(Order, pk=int(request.POST['order_id']))
order.remove_item(item_id)
if order.is_empty(): # if the last item is deleted
order.untie(request.session)
order.delete()
return HttpResponse()
您可以在实例化执行相同操作的表单集时使用 'can_delete',而不是使用 {{ form.DELETE }} 手动创建隐藏字段。例如,
ArticleFormSet = formset_factory(ArticleForm, can_delete=True)
Django 说,我应该这样渲染 inline formset
:
{{ formset.management_form }}
{% for form in formset %}
{{ form.id }}
{{ form.field_1 }}
{{ form.field_2 }}
<button type="button"> delete </button>
{% endfor %}
<button type="submit"> submit </button>
好的。但是,如果我想动态删除一些 formset 对象 (form
) 怎么办?用户按下 delete
按钮 - 我从 DOM 中删除 form
,我使用 ajax 从数据库中删除与 form
相关的对象。到目前为止它工作正常。但是当用户点击 submit
- 我的 views.py 试图验证 formset:
filled_formset = OrderItemFormSet(request.POST, instance=order)
if filled_formset.is_valid():
并引发错误:
MultiValueDictKeyError at /order/cart/
"'orderitem_set-0-id'"
...\market\ordersys\views.py in show_cart
59. if filled_formset.is_valid():
我认为它发生是因为 form
对象被 django 以某种规律性显示(第一个形式得到 id = orderitem_set-0-id
,第二个 = orderitem_set-1-id
等)当我首先删除form
从 DOM 开始,规律性被打破了 - 不再有 form
和 orderitem_set-0-id
。但 is_valid()
仍在努力获得它 dict["orderitem_set-0-id"]
。
我可以使用一些黑魔法,替换显示在 DOM 中的 django 的技术信息,恢复被破坏的规律性,但是有没有更好的方法?
你能告诉我如何正确地动态删除 formset 项目吗?
我有一段时间没有得到答案,所以我没有找到比下面更好的解决方案。也许有人会觉得它有用。
好的,诀窍是 - 在模板中的 formset
中为任何 form
设置 {{form.DELETE}}
。它呈现为一个复选框(我让它不可见)并且我让 JS 使它成为 "checked" 每当用户按下 "delete" 按钮时。用户按下 "submit" 按钮后,每个标记为删除的 form
将不会在 filled_formset.is_valid()
期间由视图验证。这使您可以在后台使用 ajax 从数据库中删除对象。
The problem was that an ERROR was raised during formset validation. Caused by the form of an object, which was already deleted from database with ajax.
所以有所有组件:
views.py
def show_cart(request):
OrderItemFormSet = inlineformset_factory(Order, OrderItem, form=OrderItemForm, extra=0, can_delete=True)
order = Order.objects.get(pk=request.session['order'])
if request.method == 'GET':
formset = OrderItemFormSet(instance=order)
return render(request, 'ordersys/cart.html', {'formset': formset})
elif request.method == 'POST':
filled_formset = OrderItemFormSet(request.POST, instance=order)
if filled_formset.is_valid():
filled_formset.save()
return redirect('catalog:index')
else:
return render(request, 'ordersys/cart.html', {'formset': filled_formset})
cart.html
<form action="" method="post">
{{ formset.management_form }}
{% for form in formset %}
{{ form.id }}
{{ form.DELETE|add_class:"not_displayed" }} # custom filter
<img src="{{ form.instance.spec_prod.product.picture.url }}">
{{ form.quantity.label_tag }}
{{ form.quantity }}
{{ form.errors }}
<button type="button">Delete</button>
{% endfor %}
<button type="submit">Submit</button>
</form>
接下来,如果用户按下 'DELETE' 按钮,我的 JavaScript
1. 用 $(item).css('display', 'none');
隐藏 form
2. 使用 ItemDelCheckbox.prop('checked', true);
选中 form.DELETE
复选框
3. 发送 ajax 请求从数据库中删除项目(否则如果用户刷新页面,该项目仍在购物车中)
views.py
def delete_order_item(request): # meets the ajax request
item_id = int(request.POST['item_id'])
order = get_object_or_404(Order, pk=int(request.POST['order_id']))
order.remove_item(item_id)
if order.is_empty(): # if the last item is deleted
order.untie(request.session)
order.delete()
return HttpResponse()
您可以在实例化执行相同操作的表单集时使用 'can_delete',而不是使用 {{ form.DELETE }} 手动创建隐藏字段。例如,
ArticleFormSet = formset_factory(ArticleForm, can_delete=True)