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.
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): 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: The second approach might involve assigning the error message to both fields
# Only do something if both fields are valid so far. involved. To do this we will move the validation code to the form's ``clean()``
if "help" not in subject: method, which is a convenient place for form-wide validation and has access to
raise forms.ValidationError("Did not send for 'help' in " the form instance and it's ``_errors`` property. Our new code (replacing the
"the subject despite CC'ing yourself.") previous sample) looks like this::
# 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