1
0
mirror of https://github.com/django/django.git synced 2025-07-07 11:19:12 +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:
Honza Král 2009-08-12 16:37:20 +00:00
parent 244296ffbc
commit b28332cd46

View File

@ -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`` 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 the form's performing validation on more than one field at a time, so a
``clean()`` method is a good spot to do this. Notice that we are talking about ``ComplexValidator`` is a good start. The complex validators are run in the
the ``clean()`` method on the form here, whereas earlier we were writing a form's ``clean()`` after the individual fields have been validated. This is the
``clean()`` method on a field. It's important to keep the field and form main difference against simple validators. It is important to realize that,
difference clear when working out where to validate things. Fields are single even if defined in very similar way, simple and complex validators are run in
data points, forms are a collection of fields. 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 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 clean methods will have been run (the previous two sections), so the
``self.cleaned_data`` will be populated with any data that has survived so validator's ``all_values`` argument will be populated with any data that has
far. So you also need to remember to allow for the fact that the fields you survived so far. So you also need to remember to allow for the fact that the
are wanting to validate might not have survived the initial individual field fields you are wanting to validate might not have survived the initial
checks. individual field checks.
There are two way to report any errors from this step. Probably the most Complex validator is run on the form, but reports it's error with the field. As
common method is to display the error at the top of the form. To create such with simple validators, all complex validators for a given field are run if the
an error, you can raise a ``ValidationError`` from the ``clean()`` method. For field has passed cleaning and their errors are aggregated and reported.
example::
class ContactForm(forms.Form): To create a complex validator, simply subclass ``ComplexValidator`` and supply
# Everything as before. your validation logic in it's ``__call__()`` method, for example::
...
def clean(self): class ValidateHelpInSubjectIfCCingMyself(ComplexValidator):
cleaned_data = self.cleaned_data def __call__(self, all_values={}, obj=None):
cc_myself = cleaned_data.get("cc_myself") cc_myself = self.get_value('cc_myself', all_values, obj)
subject = cleaned_data.get("subject")
if cc_myself and subject: if cc_myself and "help" not in value:
# Only do something if both fields are valid so far.
if "help" not in subject:
raise forms.ValidationError("Did not send for 'help' in " raise forms.ValidationError("Did not send for 'help' in "
"the subject despite CC'ing yourself.") "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 class ContactForm(forms.Form):
error message at the top of the form (normally) describing the problem. subject = forms.CharField(max_length=100,
validators=[ValidateHelpInSubjectIfCCingMyself()])
...
# Everything as before.
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 The second approach might involve assigning the error message to both fields
"cc_myself" rows in the form display. Be careful when doing this in practice, involved. To do this we will move the validation code to the form's ``clean()``
since it can lead to confusing form output. We're showing what is possible method, which is a convenient place for form-wide validation and has access to
here and leaving it up to you and your designers to work out what works the form instance and it's ``_errors`` property. Our new code (replacing the
effectively in your particular situation. Our new code (replacing the previous previous sample) looks like this::
sample) looks like this::
from django.forms.util import ErrorList from django.forms.util import ErrorList