【问题标题】:How to dynamically delete object using django formset如何使用 django formset 动态删除对象
【发布时间】:2018-06-05 20:22:09
【问题描述】:

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>

好的。但是如果我想动态删除一些表单集对象(form)怎么办?用户按下delete 按钮-我从DOM 中删除form,我使用ajax 从数据库中删除与form 相关的对象。到目前为止它工作正常。但是当用户点击submit - 我的views.py 试图验证表单集:

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 等)当我从 DOM 中删除第一个 form 时,规律性被打破 - 没有更多的formorderitem_set-0-id。但是is_valid() 仍在尝试获取它dict["orderitem_set-0-id"]

我可以使用一些黑魔法,替换django的技术信息,显示在DOM中,恢复被破坏的规律,但是有没有更好的方法?

您能告诉我如何正确地动态删除表单集项目吗?

【问题讨论】:

    标签: python django django-forms inline-formset


    【解决方案1】:

    我有一段时间没有得到答案,所以我没有找到比下面更好的解决方案。也许有人会觉得它很有用。

    好的,诀窍是 - 在模板中的 formset 中为任何 form 设置 {{form.DELETE}}。它呈现为一个复选框(我使其不可见),并且每当用户按下“删除”按钮时,我都会让 JS 使其“被选中”。用户按下“提交”按钮后,每个标记为删除的formfilled_formset.is_valid() 期间将不会被视图验证。这使您可以在后台使用 ajax 从数据库中删除对象。

    问题是在表单集验证期间引发了错误。对象的形式造成的,已经用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. 隐藏form$(item).css('display', 'none');
    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()
    

    【讨论】:

      【解决方案2】:

      您可以在实例化执行相同操作的表单集时使用“can_delete”,而不是使用 {{ form.DELETE }} 手动创建隐藏字段。例如,

      ArticleFormSet = formset_factory(ArticleForm, can_delete=True)
      

      参考can_delete

      【讨论】:

      • 如果不添加 {{ form.DELETE }} 如何检测已删除的表单?
      猜你喜欢
      • 1970-01-01
      • 2017-06-13
      • 2015-10-29
      • 2013-11-14
      • 2014-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-16
      相关资源
      最近更新 更多