mirror of
				https://github.com/django/django.git
				synced 2025-10-26 07:06:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			417 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			417 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| .. _form-and-field-validation:
 | |
| 
 | |
| Form and field validation
 | |
| =========================
 | |
| 
 | |
| Form validation happens when the data is cleaned. If you want to customize
 | |
| this process, there are various places you can change, each one serving a
 | |
| different purpose. Three types of cleaning methods are run during form
 | |
| processing. These are normally executed when you call the ``is_valid()``
 | |
| method on a form. There are other things that can trigger cleaning and
 | |
| validation (accessing the ``errors`` attribute or calling ``full_clean()``
 | |
| directly), but normally they won't be needed.
 | |
| 
 | |
| In general, any cleaning method can raise ``ValidationError`` if there is a
 | |
| problem with the data it is processing, passing the relevant information to
 | |
| the ``ValidationError`` constructor. :ref:`See below <raising-validation-error>`
 | |
| for the best practice in raising ``ValidationError``. If no ``ValidationError``
 | |
| is raised, the method should return the cleaned (normalized) data as a Python
 | |
| object.
 | |
| 
 | |
| Most validation can be done using `validators`_ - simple helpers that can be
 | |
| reused easily. Validators are simple functions (or callables) that take a single
 | |
| argument and raise ``ValidationError`` on invalid input. Validators are run
 | |
| after the field's ``to_python`` and ``validate`` methods have been called.
 | |
| 
 | |
| Validation of a Form is split into several steps, which can be customized or
 | |
| overridden:
 | |
| 
 | |
| * The ``to_python()`` method on a Field is the first step in every
 | |
|   validation. 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. For example, a
 | |
|   FloatField will turn the data into a Python ``float`` or raise a
 | |
|   ``ValidationError``.
 | |
| 
 | |
| * The ``validate()`` method on a Field 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.
 | |
|   This method does not return anything and shouldn't alter the value. You
 | |
|   should override it to handle validation logic that you can't or don't
 | |
|   want to put in a validator.
 | |
| 
 | |
| * The ``run_validators()`` method on a Field runs all of the field's
 | |
|   validators and aggregates all the errors into a single
 | |
|   ``ValidationError``. You shouldn't need to override this method.
 | |
| 
 | |
| * The ``clean()`` method on a Field subclass. This is responsible for
 | |
|   running ``to_python``, ``validate`` and ``run_validators`` in the correct
 | |
|   order and propagating their errors. If, at any time, any of the methods
 | |
|   raise ``ValidationError``, the validation stops and that error is raised.
 | |
|   This method returns the clean data, which is then inserted into the
 | |
|   ``cleaned_data`` dictionary of the form.
 | |
| 
 | |
| * The ``clean_<fieldname>()`` method in a form subclass -- where
 | |
|   ``<fieldname>`` is replaced with the name of the form field attribute.
 | |
|   This method does any cleaning that is specific to that particular
 | |
|   attribute, unrelated to the type of field that it is. 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).
 | |
| 
 | |
|   For example, if you wanted to validate that the contents of a
 | |
|   ``CharField`` called ``serialnumber`` was unique,
 | |
|   ``clean_serialnumber()`` would be the right place to do this. You don't
 | |
|   need a specific field (it's just a ``CharField``), but you want a
 | |
|   formfield-specific piece of validation and, possibly,
 | |
|   cleaning/normalizing the data.
 | |
| 
 | |
|   This method should return the cleaned value obtained from cleaned_data,
 | |
|   regardless of whether it changed anything or not.
 | |
| 
 | |
| * The Form subclass's ``clean()`` method. This method can perform
 | |
|   any validation that requires access to multiple fields from the form at
 | |
|   once. This is where you might put in things to check that if field ``A``
 | |
|   is supplied, field ``B`` must contain a valid email address and the
 | |
|   like. This method can return a completely different dictionary if it wishes,
 | |
|   which will be used as the ``cleaned_data``.
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   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
 | |
|   :meth:`~django.forms.Form.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
 | |
|   :meth:`~django.forms.Form.add_error()`.
 | |
| 
 | |
|   Also note that there are special considerations when overriding
 | |
|   the ``clean()`` method of a ``ModelForm`` subclass. (see the
 | |
|   :ref:`ModelForm documentation
 | |
|   <overriding-modelform-clean-method>` for more information)
 | |
| 
 | |
| These methods are run in the order given above, one field at a time.  That is,
 | |
| for each field in the form (in the order they are declared in the form
 | |
| definition), the ``Field.clean()`` method (or its override) is run, then
 | |
| ``clean_<fieldname>()``. Finally, once those two methods are run for every
 | |
| field, the ``Form.clean()`` method, or its override, is executed whether or not
 | |
| the previous methods have raised errors.
 | |
| 
 | |
| Examples of each of these methods are provided below.
 | |
| 
 | |
| As mentioned, any of these methods can raise a ``ValidationError``. For any
 | |
| field, if the ``Field.clean()`` method raises a ``ValidationError``, any
 | |
| field-specific cleaning method is not called. However, the cleaning methods
 | |
| for all remaining fields are still executed.
 | |
| 
 | |
| .. _raising-validation-error:
 | |
| 
 | |
| Raising ``ValidationError``
 | |
| ---------------------------
 | |
| 
 | |
| In order to make error messages flexible and easy to override, consider the
 | |
| following guidelines:
 | |
| 
 | |
| * Provide a descriptive error ``code`` to the constructor::
 | |
| 
 | |
|       # Good
 | |
|       ValidationError(_('Invalid value'), code='invalid')
 | |
| 
 | |
|       # Bad
 | |
|       ValidationError(_('Invalid value'))
 | |
| 
 | |
| * Don't coerce variables into the message; use placeholders and the ``params``
 | |
|   argument of the constructor::
 | |
| 
 | |
|       # Good
 | |
|       ValidationError(
 | |
|           _('Invalid value: %(value)s'),
 | |
|           params={'value': '42'},
 | |
|       )
 | |
| 
 | |
|       # Bad
 | |
|       ValidationError(_('Invalid value: %s') % value)
 | |
| 
 | |
| * Use mapping keys instead of positional formatting. This enables putting
 | |
|   the variables in any order or omitting them altogether when rewriting the
 | |
|   message::
 | |
| 
 | |
|       # Good
 | |
|       ValidationError(
 | |
|           _('Invalid value: %(value)s'),
 | |
|           params={'value': '42'},
 | |
|       )
 | |
| 
 | |
|       # Bad
 | |
|       ValidationError(
 | |
|           _('Invalid value: %s'),
 | |
|           params=('42',),
 | |
|       )
 | |
| 
 | |
| * Wrap the message with ``gettext`` to enable translation::
 | |
| 
 | |
|       # Good
 | |
|       ValidationError(_('Invalid value'))
 | |
| 
 | |
|       # Bad
 | |
|       ValidationError('Invalid value')
 | |
| 
 | |
| Putting it all together::
 | |
| 
 | |
|     raise ValidationError(
 | |
|         _('Invalid value: %(value)s'),
 | |
|         code='invalid',
 | |
|         params={'value': '42'},
 | |
|     )
 | |
| 
 | |
| Following these guidelines is particularly necessary if you write reusable
 | |
| forms, form fields, and model fields.
 | |
| 
 | |
| While not recommended, if you are at the end of the validation chain
 | |
| (i.e. your form ``clean()`` method) and you know you will *never* need
 | |
| to override your error message you can still opt for the less verbose::
 | |
| 
 | |
|     ValidationError(_('Invalid value: %s') % value)
 | |
| 
 | |
| .. versionadded:: 1.7
 | |
| 
 | |
| The :meth:`Form.errors.as_data() <django.forms.Form.errors.as_data()>` and
 | |
| :meth:`Form.errors.as_json() <django.forms.Form.errors.as_json()>` methods
 | |
| greatly benefit from fully featured ``ValidationError``\s (with a ``code`` name
 | |
| and a ``params`` dictionary).
 | |
| 
 | |
| Raising multiple errors
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| If you detect multiple errors during a cleaning method and wish to signal all
 | |
| of them to the form submitter, it is possible to pass a list of errors to the
 | |
| ``ValidationError`` constructor.
 | |
| 
 | |
| As above, it is recommended to pass a list of ``ValidationError`` instances
 | |
| with ``code``\s and ``params`` but a list of strings will also work::
 | |
| 
 | |
|     # Good
 | |
|     raise ValidationError([
 | |
|         ValidationError(_('Error 1'), code='error1'),
 | |
|         ValidationError(_('Error 2'), code='error2'),
 | |
|     ])
 | |
| 
 | |
|     # Bad
 | |
|     raise ValidationError([
 | |
|         _('Error 1'),
 | |
|         _('Error 2'),
 | |
|     ])
 | |
| 
 | |
| Using validation in practice
 | |
| ----------------------------
 | |
| 
 | |
| The previous sections explained how validation works in general for forms.
 | |
| Since it can sometimes be easier to put things into place by seeing each
 | |
| feature in use, here are a series of small examples that use each of the
 | |
| previous features.
 | |
| 
 | |
| .. _validators:
 | |
| 
 | |
| Using validators
 | |
| ~~~~~~~~~~~~~~~~
 | |
| 
 | |
| Django's form (and model) fields support use of simple utility functions and
 | |
| classes known as validators. A validator is merely a callable object or
 | |
| function that takes a value and simply returns nothing if the value is valid or
 | |
| raises a :exc:`~django.core.exceptions.ValidationError` if not. These can be
 | |
| passed to a field's constructor, via the field's ``validators`` argument, or
 | |
| defined on the :class:`~django.forms.Field` class itself with the
 | |
| ``default_validators`` attribute.
 | |
| 
 | |
| Simple validators can be used to validate values inside the field, let's have
 | |
| a look at Django's ``SlugField``::
 | |
| 
 | |
|     from django.forms import CharField
 | |
|     from django.core import validators
 | |
| 
 | |
|     class SlugField(CharField):
 | |
|         default_validators = [validators.validate_slug]
 | |
| 
 | |
| As you can see, ``SlugField`` is just a ``CharField`` with a customized
 | |
| validator that validates that submitted text obeys to some character rules.
 | |
| This can also be done on field definition so::
 | |
| 
 | |
|     slug = forms.SlugField()
 | |
| 
 | |
| is equivalent to::
 | |
| 
 | |
|     slug = forms.CharField(validators=[validators.validate_slug])
 | |
| 
 | |
| Common cases such as validating against an email or a regular expression can be
 | |
| handled using existing validator classes available in Django. For example,
 | |
| ``validators.validate_slug`` is an instance of
 | |
| a :class:`~django.core.validators.RegexValidator` constructed with the first
 | |
| argument being the pattern: ``^[-a-zA-Z0-9_]+$``. See the section on
 | |
| :doc:`writing validators </ref/validators>` to see a list of what is already
 | |
| available and for an example of how to write a validator.
 | |
| 
 | |
| Form field default cleaning
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| Let's firstly create a custom form field that validates its input is a string
 | |
| containing comma-separated email addresses. The full class looks like this::
 | |
| 
 | |
|     from django import forms
 | |
|     from django.core.validators import validate_email
 | |
| 
 | |
|     class MultiEmailField(forms.Field):
 | |
|         def to_python(self, value):
 | |
|             "Normalize data to a list of strings."
 | |
| 
 | |
|             # Return an empty list if no input was given.
 | |
|             if not value:
 | |
|                 return []
 | |
|             return value.split(',')
 | |
| 
 | |
|         def validate(self, value):
 | |
|             "Check if value consists only of valid emails."
 | |
| 
 | |
|             # Use the parent's handling of required fields, etc.
 | |
|             super(MultiEmailField, self).validate(value)
 | |
| 
 | |
|             for email in value:
 | |
|                 validate_email(email)
 | |
| 
 | |
| Every form that uses this field will have these methods run before anything
 | |
| else can be done with the field's data. This is cleaning that is specific to
 | |
| this type of field, regardless of how it is subsequently used.
 | |
| 
 | |
| Let's create a simple ``ContactForm`` to demonstrate how you'd use this
 | |
| field::
 | |
| 
 | |
|     class ContactForm(forms.Form):
 | |
|         subject = forms.CharField(max_length=100)
 | |
|         message = forms.CharField()
 | |
|         sender = forms.EmailField()
 | |
|         recipients = MultiEmailField()
 | |
|         cc_myself = forms.BooleanField(required=False)
 | |
| 
 | |
| Simply use ``MultiEmailField`` like any other form field. When the
 | |
| ``is_valid()`` method is called on the form, the ``MultiEmailField.clean()``
 | |
| method will be run as part of the cleaning process and it will, in turn, call
 | |
| the custom ``to_python()`` and ``validate()`` methods.
 | |
| 
 | |
| Cleaning a specific field attribute
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| Continuing on from the previous example, suppose that in our ``ContactForm``,
 | |
| we want to make sure that the ``recipients`` field always contains the address
 | |
| ``"fred@example.com"``. This is validation that is specific to our form, so we
 | |
| don't want to put it into the general ``MultiEmailField`` class. Instead, we
 | |
| write a cleaning method that operates on the ``recipients`` field, like so::
 | |
| 
 | |
|     from django import forms
 | |
| 
 | |
|     class ContactForm(forms.Form):
 | |
|         # Everything as before.
 | |
|         ...
 | |
| 
 | |
|         def clean_recipients(self):
 | |
|             data = self.cleaned_data['recipients']
 | |
|             if "fred@example.com" not in data:
 | |
|                 raise forms.ValidationError("You have forgotten about Fred!")
 | |
| 
 | |
|             # Always return the cleaned data, whether you have changed it or
 | |
|             # not.
 | |
|             return data
 | |
| 
 | |
| Sometimes you may want to add an error message to a particular field from the
 | |
| form's ``clean()`` method, in which case you can use
 | |
| :meth:`~django.forms.Form.add_error()`. Note that this won't always be
 | |
| appropriate and the more typical situation is to raise a ``ValidationError``
 | |
| from , which is turned into a form-wide error that is available through the
 | |
| :meth:`Form.non_field_errors() <django.forms.Form.non_field_errors>` method.
 | |
| 
 | |
| Cleaning and validating fields that depend on each other
 | |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| 
 | |
| .. method:: django.forms.Form.clean()
 | |
| 
 | |
| Suppose we add another requirement to our contact form: if the ``cc_myself``
 | |
| field is ``True``, the ``subject`` must contain the word ``"help"``. We are
 | |
| performing validation on more than one field at a time, so the form's
 | |
| ``clean()`` method is a good spot to do this. Notice that we are talking about
 | |
| the ``clean()`` method on the form here, whereas earlier we were writing a
 | |
| ``clean()`` method on a field. It's important to keep the field and form
 | |
| difference clear when working out where to validate things. Fields are single
 | |
| data points, forms are a collection of fields.
 | |
| 
 | |
| By the time the form's ``clean()`` method is called, all the individual field
 | |
| clean methods will have been run (the previous two sections), so
 | |
| ``self.cleaned_data`` will be populated with any data that has survived so
 | |
| far. So you also need to remember to allow for the fact that the fields you
 | |
| are wanting to validate might not have survived the initial individual field
 | |
| checks.
 | |
| 
 | |
| There are two ways to report any errors from this step. Probably the most
 | |
| common method is to display the error at the top of the form. To create such
 | |
| an error, you can raise a ``ValidationError`` from the ``clean()`` method. For
 | |
| example::
 | |
| 
 | |
|     from django import forms
 | |
| 
 | |
|     class ContactForm(forms.Form):
 | |
|         # Everything as before.
 | |
|         ...
 | |
| 
 | |
|         def clean(self):
 | |
|             cleaned_data = super(ContactForm, self).clean()
 | |
|             cc_myself = cleaned_data.get("cc_myself")
 | |
|             subject = cleaned_data.get("subject")
 | |
| 
 | |
|             if cc_myself and subject:
 | |
|                 # Only do something if both fields are valid so far.
 | |
|                 if "help" not in subject:
 | |
|                     raise forms.ValidationError("Did not send for 'help' in "
 | |
|                             "the subject despite CC'ing yourself.")
 | |
| 
 | |
| .. versionchanged:: 1.7
 | |
| 
 | |
|     In previous versions of Django, ``form.clean()`` was required to return
 | |
|     a dictionary of ``cleaned_data``. This method may still return a dictionary
 | |
|     of data to be used, but it's no longer required.
 | |
| 
 | |
| In this code, if the validation error is raised, the form will display an
 | |
| error message at the top of the form (normally) describing the problem.
 | |
| 
 | |
| Note that the call to ``super(ContactForm, self).clean()`` in the example code
 | |
| ensures that any validation logic in parent classes is maintained.
 | |
| 
 | |
| The second approach might involve assigning the error message to one of the
 | |
| fields. In this case, let's assign an error message to both the "subject" and
 | |
| "cc_myself" rows in the form display. Be careful when doing this in practice,
 | |
| since it can lead to confusing form output. We're showing what is possible
 | |
| here and leaving it up to you and your designers to work out what works
 | |
| effectively in your particular situation. Our new code (replacing the previous
 | |
| sample) looks like this::
 | |
| 
 | |
|     from django import forms
 | |
| 
 | |
|     class ContactForm(forms.Form):
 | |
|         # Everything as before.
 | |
|         ...
 | |
| 
 | |
|         def clean(self):
 | |
|             cleaned_data = super(ContactForm, self).clean()
 | |
|             cc_myself = cleaned_data.get("cc_myself")
 | |
|             subject = cleaned_data.get("subject")
 | |
| 
 | |
|             if cc_myself and subject and "help" not in subject:
 | |
|                 msg = "Must put 'help' in subject when cc'ing yourself."
 | |
|                 self.add_error('cc_myself', msg)
 | |
|                 self.add_error('subject', msg)
 | |
| 
 | |
| The second argument of ``add_error()`` can be a simple string, or preferably
 | |
| an instance of ``ValidationError``. See :ref:`raising-validation-error` for
 | |
| more details. Note that ``add_error()` automatically removes the field
 | |
| from ``cleaned_data``.
 |