1
0
mirror of https://github.com/django/django.git synced 2025-07-07 11:19:12 +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. ``ValidationError`` constructor.
Most validation can be done using `validators`_ - simple helpers that can be Most validation can be done using `validators`_ - simple helpers that can be
reused easily. There are two types of validators: reused easily. Validators are simple functions (or callables) that take a single
argument and raise ``ValidationError`` on invalid input. Validators are run
* Simple validators are simple functions (or callables) that take a single inside the ``run_validators`` method that is called from ``Field.clean`` once
argument and raises ``ValidationError`` on invalid input. Simple the value is validated by the field's methods.
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.
Validation of a Form is split into several steps, which can be customized or Validation of a Form is split into several steps, which can be customized or
overridden: overridden:
@ -59,10 +44,10 @@ overridden:
raises ``ValidationError`` on any error. This method does not return raises ``ValidationError`` on any error. This method does not return
anything and shouldn't alter the value. 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 aggregates all the errors from all validators run into a single
``ValidationError``. ``ValidationError``.
* The ``clean()`` method on a Field subclass. This is responsible for * The ``clean()`` method on a Field subclass. This is responsible for
running ``to_python``, ``validate`` and ``run_validators`` in the correct running ``to_python``, ``validate`` and ``run_validators`` in the correct
order and propagate their errors. If, at any time, any of the methods 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 should return the cleaned data, regardless of whether it changed
anything or not. 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 * The Form subclass's ``clean()`` method. This method can perform
any validation that requires access to multiple fields from the form at 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`` 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, 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 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 definition), the ``Field.clean()`` method (or its override) is run, then
``clean_<fieldname>()``. Once those two methods are run for every ``clean_<fieldname>()``. Finally, once those two methods are run for every
field, the complex validators are run for every field and, finally, field, the ``Form.clean()`` method, or its override, is executed.
``Form.clean()`` method, or its override, is executed.
Examples of each of these methods are provided below. 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`` 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 field is ``True``, the ``subject`` must contain the word ``"help"``. We are
performing validation on more than one field at a time, so a performing validation on more than one field at a time, so the form's
``ComplexValidator`` is a good start. The complex validators are run in the ``clean()`` method is a good spot to do this. Notice that we are talking about
form's ``clean()`` after the individual fields have been validated. This is the the ``clean()`` method on the form here, whereas earlier we were writing a
main difference against simple validators. It is important to realize that, ``clean()`` method on a field. It's important to keep the field and form
even if defined in very similar way, simple and complex validators are run in difference clear when working out where to validate things. Fields are single
different places in the code. Simple validators on a field (single data point), data points, forms are a collection of fields.
complex validator on a form (collection of fields).
By the time the field's complex validators are called, all the individual field 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 the clean methods will have been run (the previous two sections), so
validator's ``all_values`` argument will be populated with any data that has ``self.cleaned_data`` will be populated with any data that has survived so
survived so far. So you also need to remember to allow for the fact that the far. So you also need to remember to allow for the fact that the fields you
fields you are wanting to validate might not have survived the initial are wanting to validate might not have survived the initial individual field
individual field checks. checks.
Complex validator is run on the form, but reports it's error with the field. As There are two way to report any errors from this step. Probably the most
with simple validators, all complex validators for a given field are run if the common method is to display the error at the top of the form. To create such
field has passed cleaning and their errors are aggregated and reported. an error, you can raise a ``ValidationError`` from the ``clean()`` method. For
example::
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.")
class ContactForm(forms.Form): class ContactForm(forms.Form):
subject = forms.CharField(max_length=100,
validators=[ValidateHelpInSubjectIfCCingMyself()])
...
# Everything as before. # 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 if cc_myself and subject:
involved. To do this we will move the validation code to the form's ``clean()`` # Only do something if both fields are valid so far.
method, which is a convenient place for form-wide validation and has access to if "help" not in subject:
the form instance and it's ``_errors`` property. Our new code (replacing the raise forms.ValidationError("Did not send for 'help' in "
previous sample) looks like this:: "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 from django.forms.util import ErrorList