Opened 5 years ago

Last modified 5 years ago

#14009 new Bug

custom formset validation documentation is incomplete

Reported by: splatEric <mike@…> Owned by: nobody
Component: Documentation Version: 1.2
Severity: Normal Keywords: formset validation
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


The example for performing custom formset validation is incomplete. It does not take into account deleted forms, or empty forms for checking the unique titles constraint. It should read something along the lines of (changes highlighted by *>):

>>> class BaseArticleFormSet(BaseFormSet):
...     def clean(self):
...         """Checks that no two articles have the same title."""
...         if any(self.errors):
...             # Don't bother validating the formset unless each form is valid on its own
...             return
...         titles = []
...         for i in range(0, self.total_form_count()):
*>             if self.can_delete and self._should_delete_form(form):
*>                continue
...             form = self.forms[i]
*>             if 'title' in form.cleaned_data:
...                 title = form.cleaned_data['title']
...                 if title in titles:
...                     raise forms.ValidationError, "Articles in a set must have distinct titles."
...                 titles.append(title)

Change History (5)

comment:1 Changed 5 years ago by gabrielhurley

  • Has patch unset
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

Accepted. For future reference, the file in question is docs/topics/forms/formsets/.

comment:2 Changed 5 years ago by leonelfreire

  • Severity set to Normal
  • Type set to Uncategorized


I think there's an "error" with the above suggestion too. self.errors will contain the errors of all forms (even if the form is marked for deletion). Supposing all NOT DELETED forms are valid, if some deleted form is in an invalid state, the code:

if any(self.errors):

will make the "clean" method return too soon, avoiding the execution of the validation of the NOT DELETED forms.

AFAIK, formset.is_valid() can be True, even if formset.errors contains forms errors (from deleted forms).

In my case, I did something like:

def clean(self)
	if self.is_valid():
			# Get only the forms not marked for deletion
			cleaned_forms = list(set(self.forms) - set(self.deleted_forms))
		except AttributError: # There're no forms marked for deletion (no self.deleted_forms)
			cleaned_forms = self.forms
		# validate logic with cleaned_forms

If there's a better way to do this, let me know.

comment:3 Changed 4 years ago by julien

  • Type changed from Uncategorized to Bug

comment:4 Changed 4 years ago by aaugustin

  • UI/UX unset

Change UI/UX from NULL to False.

comment:5 Changed 4 years ago by aaugustin

  • Easy pickings unset

Change Easy pickings from NULL to False.

Note: See TracTickets for help on using tickets.
Back to Top