summaryrefslogtreecommitdiff
path: root/docs/ref
diff options
context:
space:
mode:
authorHonza Král <honza.kral@gmail.com>2009-08-12 16:37:20 +0000
committerHonza Král <honza.kral@gmail.com>2009-08-12 16:37:20 +0000
commitb28332cd462b3aec9fe595ae2c530cf23c949530 (patch)
tree6c03768a59f9ec386cbe0cc5a7d85ab6dc33dab4 /docs/ref
parent244296ffbcef59e8d3feebc6ab4f6d059e6c38ca (diff)
[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
Diffstat (limited to 'docs/ref')
-rw-r--r--docs/ref/forms/validation.txt74
1 files changed, 35 insertions, 39 deletions
diff --git a/docs/ref/forms/validation.txt b/docs/ref/forms/validation.txt
index ed6f41e30a..0f2b545df5 100644
--- a/docs/ref/forms/validation.txt
+++ b/docs/ref/forms/validation.txt
@@ -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.
-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::
+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.
- class ContactForm(forms.Form):
- # Everything as before.
- ...
+To create a complex validator, simply subclass ``ComplexValidator`` and supply
+your validation logic in it's ``__call__()`` method, for example::
- def clean(self):
- cleaned_data = self.cleaned_data
- cc_myself = cleaned_data.get("cc_myself")
- subject = cleaned_data.get("subject")
+ class ValidateHelpInSubjectIfCCingMyself(ComplexValidator):
+ def __call__(self, all_values={}, obj=None):
+ cc_myself = self.get_value('cc_myself', all_values, obj)
- 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.")
+ if cc_myself and "help" not in value:
+ 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
+ class ContactForm(forms.Form):
+ subject = forms.CharField(max_length=100,
+ validators=[ValidateHelpInSubjectIfCCingMyself()])
+ ...
+ # Everything as before.
-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