summaryrefslogtreecommitdiff
path: root/docs/ref/forms
diff options
context:
space:
mode:
Diffstat (limited to 'docs/ref/forms')
-rw-r--r--docs/ref/forms/validation.txt110
1 files changed, 101 insertions, 9 deletions
diff --git a/docs/ref/forms/validation.txt b/docs/ref/forms/validation.txt
index 87c9764f64..8ab1c26831 100644
--- a/docs/ref/forms/validation.txt
+++ b/docs/ref/forms/validation.txt
@@ -12,13 +12,11 @@ validation (accessing the ``errors`` attribute or calling ``full_clean()``
directly), but normally they won't be needed.
In general, any cleaning method can raise ``ValidationError`` if there is a
-problem with the data it is processing, passing the relevant error message to
-the ``ValidationError`` constructor. If no ``ValidationError`` is raised, the
-method should return the cleaned (normalized) data as a Python object.
-
-If you detect multiple errors during a cleaning method and wish to signal all
-of them to the form submitter, it is possible to pass a list of errors to the
-``ValidationError`` constructor.
+problem with the data it is processing, passing the relevant information to
+the ``ValidationError`` constructor. :ref:`See below <raising-validation-error>`
+for the best practice in raising ``ValidationError``. If no ``ValidationError``
+is raised, the method should return the cleaned (normalized) data as a Python
+object.
Most validation can be done using `validators`_ - simple helpers that can be
reused easily. Validators are simple functions (or callables) that take a single
@@ -87,7 +85,8 @@ overridden:
"field" (called ``__all__``), which you can access via the
``non_field_errors()`` method if you need to. If you want to attach
errors to a specific field in the form, you will need to access the
- ``_errors`` attribute on the form, which is `described later`_.
+ ``_errors`` attribute on the form, which is
+ :ref:`described later <modifying-field-errors>`.
Also note that there are special considerations when overriding
the ``clean()`` method of a ``ModelForm`` subclass. (see the
@@ -116,7 +115,100 @@ should iterate through ``self.cleaned_data.items()``, possibly considering the
``_errors`` dictionary attribute on the form as well. In this way, you will
already know which fields have passed their individual validation requirements.
-.. _described later:
+.. _raising-validation-error:
+
+Raising ``ValidationError``
+---------------------------
+
+.. versionchanged:: 1.6
+
+In order to make error messages flexible and easy to override, consider the
+following guidelines:
+
+* Provide a descriptive error ``code`` to the constructor::
+
+ # Good
+ ValidationError(_('Invalid value'), code='invalid')
+
+ # Bad
+ ValidationError(_('Invalid value'))
+
+* Don't coerce variables into the message; use placeholders and the ``params``
+ argument of the constructor::
+
+ # Good
+ ValidationError(
+ _('Invalid value: %(value)s'),
+ params={'value': '42'},
+ )
+
+ # Bad
+ ValidationError(_('Invalid value: %s') % value)
+
+* Use mapping keys instead of positional formatting. This enables putting
+ the variables in any order or omitting them altogether when rewriting the
+ message::
+
+ # Good
+ ValidationError(
+ _('Invalid value: %(value)s'),
+ params={'value': '42'},
+ )
+
+ # Bad
+ ValidationError(
+ _('Invalid value: %s'),
+ params=('42',),
+ )
+
+* Wrap the message with ``gettext`` to enable translation::
+
+ # Good
+ ValidationError(_('Invalid value'))
+
+ # Bad
+ ValidationError('Invalid value')
+
+Putting it all together::
+
+ raise ValidationErrror(
+ _('Invalid value: %(value)s'),
+ code='invalid',
+ params={'value': '42'},
+ )
+
+Following these guidelines is particularly necessary if you write reusable
+forms, form fields, and model fields.
+
+While not recommended, if you are at the end of the validation chain
+(i.e. your form ``clean()`` method) and you know you will *never* need
+to override your error message you can still opt for the less verbose::
+
+ ValidationError(_('Invalid value: %s') % value)
+
+Raising multiple errors
+~~~~~~~~~~~~~~~~~~~~~~~
+
+If you detect multiple errors during a cleaning method and wish to signal all
+of them to the form submitter, it is possible to pass a list of errors to the
+``ValidationError`` constructor.
+
+As above, it is recommended to pass a list of ``ValidationError`` instances
+with ``code``\s and ``params`` but a list of strings will also work::
+
+ # Good
+ raise ValidationError([
+ ValidationError(_('Error 1'), code='error1'),
+ ValidationError(_('Error 2'), code='error2'),
+ ])
+
+ # Bad
+ raise ValidationError([
+ _('Error 1'),
+ _('Error 2'),
+ ])
+
+.. _modifying-field-errors:
Form subclasses and modifying field errors
------------------------------------------