Django: Validations during Form Processing

Fri 15 May 2015

Filed under Django

This post is mostly based on the Django Docs on Form and Field Validation. I reformatted the information in a way that feels easier to use.


There are 3 types of cleaning methods that are run during form processing. These are normally executed when you call the is_valid() method on a form.  (is_valid() runs validation routines for all fields on the form. When this method is called, if all fields contain valid data, it will:

  • return True
  • place the form’s data in its cleaned_data attribute.)

In general, any cleaning method can raise a ValidationError if there is a problem with the data it is processing; it passes the relevant information to the ValidationError constructor. 

Steps of validation

The methods below are run in the order given, one field at a time. That is, for each field in the form (in the order they are declared in the form definition). Then the form.clean(), or its override, is executed regardless if the previous methods have raised errors. If the Field.clean() method raises a ValidationError, its field-specific cleaning methods are not called. However, the cleaning methods for all remaining fields are still executed.

Normally, the clean() method will be run and it will take care of the first three validations (to_python(), validate(), run_validators()). But you can customize any of them, and when the clean() method is executed, it will run the customized method.

1. to_python() method on a Field

  • WHAT IT DOES: It coerces the value to correct datatype and raises ValidationError if that is not possible. This method accepts the raw value from the widget and returns the converted value.

  • EXAMPLE: a FloatField will turn the data into a Python float or raise a ValidationError.

  • HANDLES ERRORS: raises ValidationError on any error

  • RETURNS: returns the converted value.


2. validate() method on a Field

  • WHAT IT DOES: handles field-specific validation that is not suitable for a validator. It takes a value that has been coerced to correct datatype and raises ValidationError on any error.

  • HANDLES ERRORS: raises ValidationError on any error

  • RETURNS: This method does not return anything and shouldn’t alter the value.

  • NOTES: You should override it to handle validation logic that you can’t or don’t want to put in a validator.


3. run_validators() method on a Field

  • WHAT IT DOES: runs all of the field’s validators

  • HANDLES ERRORS: aggregates all the errors into a single ValidationError.

  • RETURNS:

  • NOTES: You shouldn’t need to override this method.


4. The clean() method on a Field subclass.

  • WHAT IT DOES: This is responsible for running to_python, validate and run_validators in the correct order and propagating their errors.

  • HANDLES ERRORS: If, at any time, any of the methods raise ValidationError, the validation stops and that error is raised.

  • RETURNS: This method returns the clean data, which is then inserted into the cleaned_data dictionary of the form.


5. The clean_<fieldname>() method in a form subclass – where <fieldname> is replaced with the name of the form field attribute.

  • WHAT IT DOES: This method does any cleaning that is specific to that particular attribute, unrelated to the type of field that it is.

  • HOW TO USE: This method is not passed any parameters. You will need to look up the value of the field in self.cleaned_data and remember that it will be a Python object at this point, not the original string submitted in the form (it will be in cleaned_data because the general field clean() method, above, has already cleaned the data once).

  • HANDLES ERRORS:

  • RETURNS: the cleaned value obtained from cleaned_data -- regardless of whether it changed anything or not.


6. The Form subclass’s clean() method.

  • WHAT IT DOES: This method can perform any validation that requires access to multiple fields from the form at once.

  • EXAMPLE: Checks that if field A is supplied, field B must contain a valid email address and the like.

  • HOW TO USE: Since the field validation methods have been run by the time clean() is called, you also have access to the form’s errors attribute which contains all the errors raised by cleaning of individual fields.

  • HANDLES ERRORS: Note that any errors raised by your Form.clean() override will not be associated with any field in particular. They go into a special “field” (called __all__), which you can access via the non_field_errors() method if you need to. If you want to attach errors to a specific field in the form, you need to call add_error().

  • RETURNS: This method can return a completely different dictionary if it wishes, which will be used as the cleaned_data.

  • NOTES: Also note that there are special considerations when overriding the clean() method of a ModelForm subclass. (see the ModelForm documentation for more information)

Raising ValidationError examples:

if not flag:
    raise ValidationError('Please submit flag')   a simple example
    raise ValidationError(_('text: %(flag)s'), 
                            code='no flag', 
                            params={'flag': '42'},)

multiple errors can be created as a list

    raise ValidationError([
        ValidationError(_('Error 1'), code='error1'),
        ValidationError(_('Error 2'), code='error2'),
    ])

Writing Validators

There are many builtin validators that match the field type (ex: EmailValidator for EmailField). Those validators can be customized too. (ex: class EmailValidator([message=None, code=None, whitelist=None])

Here's a sample custom validator:

from django.core.exceptions import ValidationError

def validate_even(value):
   if value % 2 != 0:
      raise ValidationError('%s is not an even number' % value)

Then, this validator can be used for any fields when setting up the models:

class MyModel(models.Model):
   even_field = models.IntegerField(validators=[validate_even])

It can also be used for forms:

class MyForm(forms.Form):
   even_field = forms.IntegerField(validators=[validate_even])

Validators will not be run automatically when you save a model, but if you are using a ModelForm, it will run your validators on any fields that are included in your form.


Comments


DeeKras.com © Dee Kras Powered by Pelican and Twitter Bootstrap. Icons by Font Awesome and Font Awesome More