Django: Overriding the clean() method in forms - question about raising errors
Asked Answered
S

4

9

I've been doing things like this in the clean method:

if self.cleaned_data['type'].organized_by != self.cleaned_data['organized_by']:
      raise forms.ValidationError('The type and organization do not match.')
if self.cleaned_data['start'] > self.cleaned_data['end']:
      raise forms.ValidationError('The start date cannot be later than the end date.')

But then that means that the form can only raise one of these errors at a time. Is there a way for the form to raise both of these errors?

EDIT #1: Any solutions for the above are great, but would love something that would also work in a scenario like:

if self.cleaned_data['type'].organized_by != self.cleaned_data['organized_by']:
      raise forms.ValidationError('The type and organization do not match.')
if self.cleaned_data['start'] > self.cleaned_data['end']:
      raise forms.ValidationError('The start date cannot be later than the end date.')
super(FooAddForm, self).clean()

Where FooAddForm is a ModelForm and has unique constraints that might also cause errors. If anyone knows of something like that, that would be great...

Savoirvivre answered 22/1, 2010 at 12:6 Comment(0)
M
17

From the docs:

https://docs.djangoproject.com/en/1.7/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other

from django.forms.util import ErrorList

def clean(self):

  if self.cleaned_data['type'].organized_by != self.cleaned_data['organized_by']:
    msg = 'The type and organization do not match.'
    self._errors['type'] = ErrorList([msg])
    del self.cleaned_data['type']

  if self.cleaned_data['start'] > self.cleaned_data['end']:
    msg = 'The start date cannot be later than the end date.'
    self._errors['start'] = ErrorList([msg])
    del self.cleaned_data['start']

  return self.cleaned_data
Macrae answered 22/1, 2010 at 13:41 Comment(1)
This works very nicely (I wasn't sure if I liked that the error messages were attached to the fields rather than the whole form, but it actually sort of makes more sense this way) and the ModelForm unique constraints work too. So I'm accepting this one - thanks! :)Savoirvivre
R
7
errors = []
if self.cleaned_data['type'].organized_by != self.cleaned_data['organized_by']:
      errors.append('The type and organization do not match.')
if self.cleaned_data['start'] > self.cleaned_data['end']:
     errors.append('The start date cannot be later than the end date.')

if errors:
    raise forms.ValidationError(errors)
Ralfston answered 22/1, 2010 at 12:59 Comment(1)
Grrr.... was trying to give this +1, but I accidently clicked twice and it now says "vote too old to be changed" grrr... Anyway, nice answer :) but I'm still having one problem with it... I've got one clean method on a ModelForm, where it's important to check for unique constraints, but if I do: if errors: raise forms.ValidationError(errors) super(CompetitionAddForm, self).clean() then it's either my errors or the unique constraint errors :-/Savoirvivre
O
4

Although its old post, if you want less code you can use add_error() method to add error messages. I am extending the @kemar's answer to show the used case:

add_error() automatically removes the field from cleaned_data dictionary, you dont have to delete it manually. Also you dont have to import anything to use this.

documentation is here

def clean(self):

  if self.cleaned_data['type'].organized_by != self.cleaned_data['organized_by']:
    msg = 'The type and organization do not match.'
    self.add_error('type', msg)

  if self.cleaned_data['start'] > self.cleaned_data['end']:
    msg = 'The start date cannot be later than the end date.'
    self.add_error('start', msg)

  return self.cleaned_data
Overunder answered 2/2, 2018 at 8:10 Comment(0)
N
3

If you'd prefer that the error messages be attached to the form rather than to specific fields, you can use the key "__all__" like this:

msg = 'The type and organization do not match.'
self._errors['__all__'] = ErrorList([msg])

Also, as the Django docs explain: "if you want to add a new error to a particular field, you should check whether the key already exists in self._errors or not. If not, create a new entry for the given key, holding an empty ErrorList instance. In either case, you can then append your error message to the list for the field name in question and it will be displayed when the form is displayed."

Novelize answered 9/3, 2010 at 0:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.