8

If the user fills a form in formset incompletely and then marks it for deletion, my form handling dies horribly. The deleted forms prevent formset.cleaned_data from working as they don't validate and thus the form doesn't have a cleaned_data attribute. If I try to iterate over formset.deleted_forms and delete the forms from formset.forms, then formset.cleaned_data crashes due to index out of range.

How should I be handling these invalid forms the user didn't want anyway?

( This is my error, I have copied description from google groups)

I don't understant the error because looking into django code I can read this:

def is_valid(self):
    """
    Returns True if form.errors is empty for every form in self.forms.
    """
    if not self.is_bound:
        return False
    # We loop over every form.errors here rather than short circuiting on the
    # first failure to make sure validation gets triggered for every form.
    forms_valid = True
    err = self.errors
    for i in range(0, self.total_form_count()):
        form = self.forms[i]
        if self.can_delete:                           <-------
            if self._should_delete_form(form):
                # This form is going to be deleted so any of its errors
                # should not cause the entire formset to be invalid.
                continue
        if bool(self.errors[i]):
            forms_valid = False
    return forms_valid and not bool(self.non_form_errors())

At this time, this is my code to avoid errors:

formFac = modelformset_factory(prm_model, extra = extra, can_delete = prm_can_delete )

if request.method == 'POST':
    formSet = formFac( request.POST )
    hi_ha_errors = False
    if formSet.is_valid():
        for form in formSet:
            if form not in formSet.deleted_forms:
                form.save()
        for form in formSet.deleted_forms:
            instance = form.instance
            if instance.pk:
                try:
                    instance.delete()
                except Exception, e:                    
                    form._errors.setdefault(NON_FIELD_ERRORS, []).append( 
                          'This row is referenced by others.'  )
                    hi_ha_errors = True

        if not hi_ha_errors:
            return HttpResponseRedirect( prm_url_next )     
dani herrera
  • 48,760
  • 8
  • 117
  • 177

1 Answers1

0

The way I solved this is to override the full_clean() method of my Form/ModelForm used in the Formset/ModelFormset

class MyModelForm(ModelForm):

    def full_clean(self, *args, **kwargs):
        super(MyModelForm, self).full_clean(*args, **kwargs)
        if hasattr(self, 'cleaned_data') and self.cleaned_data.get('DELETE', False):
            self._errors = ErrorDict()

If the form delete box is checked, this clears the error list.. the form will be displayed with no errors. But if the user unchecks the delete box and resubmits, then the form will show errors as normal.

little_birdie
  • 5,600
  • 3
  • 23
  • 28