5

I run into this often:

I want to hide the default delete box in formsets and delete the instance of an object if a certain field is cleared in the each form of the formset.

The typical problem is that, either validation gets in the way or this breaks the blank form detection and starts adding all forms ( even blank extra ) when the formset is saved.

2 Answers 2

5

Here is the solution I found:

This code creates a model formset, ensures it validates by permitting a blank field, and then on save determines which objects to delete and which forms to save.

TaskFormset = inlineformset_factory(User, FAQ, extra=3, can_delete=False, exclude=('user', 'answer',))
formset = TaskFormset(request.POST, request.FILES, instance=user)
for form in formset:
    form.fields['question'].required = False

// later when performing the formset save

for form in formset:
    if form.instance.pk and form.cleaned_data['question'].strip() == '':
        form.instance.delete()
    elif form.cleaned_data:
        form.save()
Sign up to request clarification or add additional context in comments.

3 Comments

u can probably add some javascript which sets the delete flag to true when the field is empty .
No Kiran, he will want to do that processing server side. Relying on javascript to do that is the same as accepting the user's judgement.
Controlling the form in the formset seems more pythonic than adding external JS code. This is easier to test and seems simpler than adding JS and CSS overhead. Thank you for the suggestions.
1

There's a method on BaseFormSet called _should_delete_form which makes it easy to automatically delete an instance based on your own criteria, however it's a "private" method so not sure about future support. You also need to save the formsets by calling formset.save().

In the example below it will delete a row if all the fields values evaluate to false values.

class MyFormSet(forms.BaseInlineFormSet):
    def _should_delete_form(self, form):
        """Return whether or not the form should be deleted."""
        if form.cleaned_data.get(forms.formsets.DELETION_FIELD_NAME):
            return True  # marked for delete
        fields = ('name', 'question', 'amount', 'measure', 'comment')
        if not any(form.cleaned_data[i] for i in fields):
            return True
        return False

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.