如何使用django formset动态删除对象

时间:2017-12-23 16:20:37

标签: python django django-forms inline-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删除与DATABASE中的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等等。)当我删除第一个{{ 1}}来自DOM,规则性被打破 - 不再有form form。但是orderitem_set-0-id仍然试图让它is_valid()

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

你能告诉我如何正确动态删除formset项吗?

2 个答案:

答案 0 :(得分:2)

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

好的,诀窍是 - 让{{form.DELETE}}模板中的form formsetform。它呈现为一个复选框(我让它变得不可见),我让JS使它'#34;检查&#34;每当用户按下&#34;删除&#34;按钮。用户按下&#34;提交&#34;标记为删除的每个filled_formset.is_valid()按钮在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}) 期间不会被视图验证。这允许您使用场景后面的ajax从数据库中删除对象。

  

问题是在formset验证期间引发了ERROR。由对象形式引起的,该对象已使用ajax从数据库中删除。

所以有所有组件:

views.py

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

cart.html

form

接下来,如果用户按下“删除”键。按钮,我的JavaScript
1.将$(item).css('display', 'none');form.DELETE一起隐藏 2.使用ItemDelCheckbox.prop('checked', true);选中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() 复选框 3.发送ajax请求以从数据库中删除项目(否则,如果用户刷新页面,该项目仍在购物车中)

views.py

 setXAuthorizationToken(client){
    let requestHeader = new Headers();
    requestHeader.append('Content-Type', 'application/x-www-form-urlencoded');
    this.http.post(client.clientURL + "oauth/token", 'grant_type=password&client_id=toto&client_secret=sec&' +  'username=' + client.username
    + '&password=' + client.password, {
      headers: requestHeader
    }).map(res=>res.json())
    .subscribe((token) =>{
      if(!token.access_token){
          return;
      }
      else{
       var decompressToken = LZString.decompressFromEncodedURIComponent(token.access_token);
       console.log(decompressToken);




}


    });
    }

答案 1 :(得分:2)

与其使用{{form.DELETE}}手动创建隐藏字段,不如在实例化相同的表单集时可以使用'can_delete'。例如,

ArticleFormSet = formset_factory(ArticleForm, can_delete=True)

引用can_delete