Ticket #12498: complex-validator-docs.diff

File complex-validator-docs.diff, 8.3 KB (added by jkocherhans, 9 years ago)

Patch to replace what was taken out in [12091].

  • docs/ref/forms/validation.txt

    diff --git a/docs/ref/forms/validation.txt b/docs/ref/forms/validation.txt
    index 54d755f..0f2b545 100644
    a b of them to the form submitter, it is possible to pass a list of errors to the 
    2323``ValidationError`` constructor.
    2424
    2525Most validation can be done using `validators`_ - simple helpers that can be
    26 reused easily. Validators are simple functions (or callables) that take a single
    27 argument and raise ``ValidationError`` on invalid input. Validators are run
    28 inside the ``run_validators`` method that is called from ``Field.clean`` once
    29 the value is validated by the field's methods.
     26reused easily. There are two types of validators:
     27
     28    * Simple validators are simple functions (or callables) that take a single
     29      argument and raises ``ValidationError`` on invalid input.  Simple
     30      validators are run inside the ``run_validators`` method that is called
     31      from ``Field.clean`` once the value is validated by the field's methods.
     32
     33    * Complex validators are instances of ``ComplexValidator`` class and,
     34      unlike simple validators, can access not just one value, but all at once.
     35      These are perfectly suited for cross field validation (one of N fields
     36      must be supplied, this field must equal that etc.)
     37
     38
     39.. warning::
     40
     41    Since complex validators must have access to all cleaned values, they must
     42    be run after individual fields have been cleaned. This means that these are run
     43    in ``Form.full_clean`` and not inside ``Field.clean`` with simple validators.
     44
    3045
    3146Validation of a Form is split into several steps, which can be customized or
    3247overridden:
    overridden: 
    4459      raises ``ValidationError`` on any error. This method does not return
    4560      anything and shouldn't alter the value.
    4661
    47     * Validators are run in the ``run_validators`` method. This method
     62    * Simple validators are run in the ``run_validators`` method. This method
    4863      aggregates all the errors from all validators run into a single
    4964      ``ValidationError``.
    50 
     65   
    5166    * The ``clean()`` method on a Field subclass. This is responsible for
    5267      running ``to_python``, ``validate`` and ``run_validators`` in the correct
    5368      order and propagate their errors. If, at any time, any of the methods
    overridden: 
    7691      should return the cleaned data, regardless of whether it changed
    7792      anything or not.
    7893
     94    * The Field's complex validators are run after all the fields have been
     95      cleaned and only on those fields that passed validation. Errors from
     96      individual validators are aggregated and all the errors are raised for a
     97      given field.
     98
    7999    * The Form subclass's ``clean()`` method. This method can perform
    80100      any validation that requires access to multiple fields from the form at
    81101      once. This is where you might put in things to check that if field ``A``
    overridden: 
    95115These methods are run in the order given above, one field at a time.  That is,
    96116for each field in the form (in the order they are declared in the form
    97117definition), the ``Field.clean()`` method (or its override) is run, then
    98 ``clean_<fieldname>()``. Finally, once those two methods are run for every
    99 field, the ``Form.clean()`` method, or its override, is executed.
     118``clean_<fieldname>()``. Once those two methods are run for every
     119field, the complex validators are run for every field and, finally,
     120``Form.clean()`` method, or its override, is executed.
    100121
    101122Examples of each of these methods are provided below.
    102123
    Cleaning and validating fields that depend on each other 
    272293
    273294Suppose we add another requirement to our contact form: if the ``cc_myself``
    274295field is ``True``, the ``subject`` must contain the word ``"help"``. We are
    275 performing validation on more than one field at a time, so the form's
    276 ``clean()`` method is a good spot to do this. Notice that we are talking about
    277 the ``clean()`` method on the form here, whereas earlier we were writing a
    278 ``clean()`` method on a field. It's important to keep the field and form
    279 difference clear when working out where to validate things. Fields are single
    280 data points, forms are a collection of fields.
    281 
    282 By the time the form's ``clean()`` method is called, all the individual field
    283 clean methods will have been run (the previous two sections), so
    284 ``self.cleaned_data`` will be populated with any data that has survived so
    285 far. So you also need to remember to allow for the fact that the fields you
    286 are wanting to validate might not have survived the initial individual field
    287 checks.
    288 
    289 There are two way to report any errors from this step. Probably the most
    290 common method is to display the error at the top of the form. To create such
    291 an error, you can raise a ``ValidationError`` from the ``clean()`` method. For
    292 example::
     296performing validation on more than one field at a time, so a
     297``ComplexValidator`` is a good start. The complex validators are run in the
     298form's ``clean()`` after the individual fields have been validated. This is the
     299main difference against simple validators. It is important to realize that,
     300even if defined in very similar way, simple and complex validators are run in
     301different places in the code. Simple validators on a field (single data point),
     302complex validator on a form (collection of fields).
     303
     304By the time the field's complex validators are called, all the individual field
     305clean methods will have been run (the previous two sections), so the
     306validator's ``all_values`` argument will be populated with any data that has
     307survived so far. So you also need to remember to allow for the fact that the
     308fields you are wanting to validate might not have survived the initial
     309individual field checks.
     310
     311Complex validator is run on the form, but reports it's error with the field. As
     312with simple validators, all complex validators for a given field are run if the
     313field has passed cleaning and their errors are aggregated and reported.
     314
     315To create a complex validator, simply subclass ``ComplexValidator`` and supply
     316your validation logic in it's ``__call__()`` method, for example::
     317
     318    class ValidateHelpInSubjectIfCCingMyself(ComplexValidator):
     319        def __call__(self, all_values={}, obj=None):
     320            cc_myself = self.get_value('cc_myself', all_values, obj)
     321
     322            if cc_myself and "help" not in value:
     323                raise forms.ValidationError("Did not send for 'help' in "
     324                        "the subject despite CC'ing yourself.")
     325               
    293326
    294327    class ContactForm(forms.Form):
    295         # Everything as before.
     328        subject = forms.CharField(max_length=100,
     329            validators=[ValidateHelpInSubjectIfCCingMyself()])
    296330        ...
     331        # Everything as before.
    297332
    298         def clean(self):
    299             cleaned_data = self.cleaned_data
    300             cc_myself = cleaned_data.get("cc_myself")
    301             subject = cleaned_data.get("subject")
    302 
    303             if cc_myself and subject:
    304                 # Only do something if both fields are valid so far.
    305                 if "help" not in subject:
    306                     raise forms.ValidationError("Did not send for 'help' in "
    307                             "the subject despite CC'ing yourself.")
    308 
    309             # Always return the full collection of cleaned data.
    310             return cleaned_data
    311 
    312 In this code, if the validation error is raised, the form will display an
    313 error message at the top of the form (normally) describing the problem.
    314333
    315 The second approach might involve assigning the error message to one of the
    316 fields. In this case, let's assign an error message to both the "subject" and
    317 "cc_myself" rows in the form display. Be careful when doing this in practice,
    318 since it can lead to confusing form output. We're showing what is possible
    319 here and leaving it up to you and your designers to work out what works
    320 effectively in your particular situation. Our new code (replacing the previous
    321 sample) looks like this::
     334The second approach might involve assigning the error message to both fields
     335involved. To do this we will move the validation code to the form's ``clean()``
     336method, which is a convenient place for form-wide validation and has access to
     337the form instance and it's ``_errors`` property. Our new code (replacing the
     338previous sample) looks like this::
    322339
    323340    from django.forms.util import ErrorList
    324341
Back to Top