如何使用Django Formset动态删除对象 [英] How to dynamically delete object using django formset

查看:147
本文介绍了如何使用Django Formset动态删除对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Django说,我应该以这种方式呈现内联表单集

Django says, i should render inline formset this way:

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

好。但是,如果我想动态删除一些表单对象(表单)怎么办?用户按下删除按钮-我从DOM中删除表单,我使用ajax删除与<$相关的对象c $ c> form 。到目前为止,一切正常。但是,当用户单击提交-我的views.py试图验证表单集时:

Ok. But what if i want to delete some formset objects (form) dynamically? User press delete button - i remove form from the DOM, i use ajax to remove object, related to the form from the DATABASE. It works ok till this point. But when user clicks submit - my views.py trying to validate 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():

我认为这是因为django显示表单对象具有一定的规律性(第一个表单的id = orderitem_set-0-id ,第二个= orderitem_set-1-id 等。)当我第一次删除 DOM中的表单,常规性被打破了-没有 orderitem_set-0-id 表单 c $ c>。但是 is_valid()仍在尝试获取它 dict [ orderitem_set-0-id]

I think it happend because form objects were displayed by django with some regularity (first form got id = orderitem_set-0-id, second = orderitem_set-1-id etc.) And when i deleted first form from the DOM, the regularity was broken - there is no more form with orderitem_set-0-id. But is_valid() still trying to get it dict["orderitem_set-0-id"].

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

I could use some black magic, substituting django's technical information, displayed in the DOM, restoring disrupted regularity, but is there a better way?

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

Could you tell me how to properly dynamically delete formset items, please ?

推荐答案

一段时间以来我没有任何答案,因此我没有找到比下面更好的解决方案。也许有人会发现它有用。

I got no answer for some time, so i did not find any better solution than below. Maybe someome will find it useful.

好的,诀窍是-拥有 {{form.DELETE}} 模板中表单集中的任何表单。每当用户按下删除按钮时,它就会显示为一个复选框(我使其变为不可见),并且使JS使其变为选中状态。用户按下提交按钮后,在 filled_formset.is_valid()表单都不会被视图验证。 c $ c>。这样一来,您就可以从后台删除带有ajax的数据库对象。

Ok, the trick is - to have {{form.DELETE}} for any form in your formset in template. It renders as a checkbox (i made it invisible) and i made JS to make it "checked" whenever user press "delete" button. After user press "submit" button, every form, marked for deletion, will NOT be validated by the view during filled_formset.is_valid(). This lets you delete object from database with ajax behind the scene.


问题是在表单集验证期间引发了错误。

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

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>

接下来,如果用户按下删除按钮,则我的JavaScript

1。用 $ {item)隐藏表单 .css('display','none');

2.使用 ItemDelCheckbox.prop('checked',true);使选中的 form.DELETE 复选框;

3.发送ajax请求从数据库中删除项目(否则,如果用户刷新页面,则该项目仍在购物车中)

Next, if user press 'DELETE' button, my JavaScript
1. hides form with $(item).css('display', 'none');
2. makes checked form.DELETE checkbox with ItemDelCheckbox.prop('checked', true);
3. sends ajax request to delete item from database (otherwise if user refreshes the page, the item still in the cart)

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

这篇关于如何使用Django Formset动态删除对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆