mirror of
https://github.com/django/django.git
synced 2025-07-07 03:09:22 +00:00
[soc2009/model-validation] Added note on ComplexValidators and multi field validation
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/model-validation@11436 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
244296ffbc
commit
b28332cd46
@ -293,53 +293,49 @@ 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 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.
|
||||
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).
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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):
|
||||
# Everything as before.
|
||||
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")
|
||||
|
||||
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::
|
||||
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::
|
||||
|
||||
from django.forms.util import ErrorList
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user