1
0
mirror of https://github.com/django/django.git synced 2025-07-06 18:59:13 +00:00

[soc2009/model-validation] Removed references in the docs to ComplexValidator. Refs [12498].

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/model-validation@12091 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Joseph Kocherhans 2010-01-04 23:52:03 +00:00
parent 82c4f9d04e
commit 1f98e98106

View File

@ -23,25 +23,10 @@ of them to the form submitter, it is possible to pass a list of errors to the
``ValidationError`` constructor.
Most validation can be done using `validators`_ - simple helpers that can be
reused easily. There are two types of validators:
* Simple validators are simple functions (or callables) that take a single
argument and raises ``ValidationError`` on invalid input. Simple
validators are run inside the ``run_validators`` method that is called
from ``Field.clean`` once the value is validated by the field's methods.
* Complex validators are instances of ``ComplexValidator`` class and,
unlike simple validators, can access not just one value, but all at once.
These are perfectly suited for cross field validation (one of N fields
must be supplied, this field must equal that etc.)
.. warning::
Since complex validators must have access to all cleaned values, they must
be run after individual fields have been cleaned. This means that these are run
in ``Form.full_clean`` and not inside ``Field.clean`` with simple validators.
reused easily. Validators are simple functions (or callables) that take a single
argument and raise ``ValidationError`` on invalid input. Validators are run
inside the ``run_validators`` method that is called from ``Field.clean`` once
the value is validated by the field's methods.
Validation of a Form is split into several steps, which can be customized or
overridden:
@ -59,10 +44,10 @@ overridden:
raises ``ValidationError`` on any error. This method does not return
anything and shouldn't alter the value.
* Simple validators are run in the ``run_validators`` method. This method
* Validators are run in the ``run_validators`` method. This method
aggregates all the errors from all validators run into a single
``ValidationError``.
* The ``clean()`` method on a Field subclass. This is responsible for
running ``to_python``, ``validate`` and ``run_validators`` in the correct
order and propagate their errors. If, at any time, any of the methods
@ -91,11 +76,6 @@ overridden:
should return the cleaned data, regardless of whether it changed
anything or not.
* The Field's complex validators are run after all the fields have been
cleaned and only on those fields that passed validation. Errors from
individual validators are aggregated and all the errors are raised for a
given field.
* 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``
@ -115,9 +95,8 @@ overridden:
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>()``. Once those two methods are run for every
field, the complex validators are run for every field and, finally,
``Form.clean()`` method, or its override, is executed.
``clean_<fieldname>()``. Finally, once those two methods are run for every
field, the ``Form.clean()`` method, or its override, is executed.
Examples of each of these methods are provided below.
@ -293,49 +272,53 @@ Cleaning and validating fields that depend on each other
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 a
``ComplexValidator`` is a good start. The complex validators are run in the
form's ``clean()`` after the individual fields have been validated. This is the
main difference against simple validators. It is important to realize that,
even if defined in very similar way, simple and complex validators are run in
different places in the code. Simple validators on a field (single data point),
complex validator on a form (collection of fields).
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 field's complex validators are called, all the individual field
clean methods will have been run (the previous two sections), so the
validator's ``all_values`` argument 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.
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.
Complex validator is run on the form, but reports it's error with the field. As
with simple validators, all complex validators for a given field are run if the
field has passed cleaning and their errors are aggregated and reported.
To create a complex validator, simply subclass ``ComplexValidator`` and supply
your validation logic in it's ``__call__()`` method, for example::
class ValidateHelpInSubjectIfCCingMyself(ComplexValidator):
def __call__(self, all_values={}, obj=None):
cc_myself = self.get_value('cc_myself', all_values, obj)
if cc_myself and "help" not in value:
raise forms.ValidationError("Did not send for 'help' in "
"the subject despite CC'ing yourself.")
There are two way 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::
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100,
validators=[ValidateHelpInSubjectIfCCingMyself()])
...
# Everything as before.
...
def clean(self):
cleaned_data = self.cleaned_data
cc_myself = cleaned_data.get("cc_myself")
subject = cleaned_data.get("subject")
The second approach might involve assigning the error message to both fields
involved. To do this we will move the validation code to the form's ``clean()``
method, which is a convenient place for form-wide validation and has access to
the form instance and it's ``_errors`` property. Our new code (replacing the
previous sample) looks like this::
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.")
# Always return the full collection of cleaned data.
return cleaned_data
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.
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.forms.util import ErrorList