[Django]-How to dynamically delete object using django formset

6👍

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

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.

So there are all components:

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>

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

1👍

Instead of manually creating the hidden field using {{ form.DELETE }}, you can probably use ‘can_delete’ while instantiating the formset which does the same. For eg,

ArticleFormSet = formset_factory(ArticleForm, can_delete=True)

Refer can_delete

Leave a comment