Commit 5b26a014 authored by Alasdair Nicol's avatar Alasdair Nicol Committed by Tim Graham
Browse files

Fixed #23865 -- documented how to assign errors to a field in Model.clean()

Also added a unit test wit the simpler syntax which we have documented,
where the dictionary values are strings.
parent a3aeba0f
Loading
Loading
Loading
Loading
+17 −3
Original line number Diff line number Diff line
@@ -200,9 +200,10 @@ access to more than a single field::
Note, however, that like :meth:`Model.full_clean()`, a model's ``clean()``
method is not invoked when you call your model's :meth:`~Model.save()` method.

Any :exc:`~django.core.exceptions.ValidationError` exceptions raised by
``Model.clean()`` will be stored in a special key error dictionary key,
:data:`~django.core.exceptions.NON_FIELD_ERRORS`, that is used for errors
In the above example, the :exc:`~django.core.exceptions.ValidationError`
exception raised by ``Model.clean()`` was instantiated with a string, so it
will be stored in a special error dictionary key,
:data:`~django.core.exceptions.NON_FIELD_ERRORS`. This key is used for errors
that are tied to the entire model instead of to a specific field::

    from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
@@ -211,6 +212,19 @@ that are tied to the entire model instead of to a specific field::
    except ValidationError as e:
        non_field_errors = e.message_dict[NON_FIELD_ERRORS]

To assign exceptions to a specific field, instantiate the
:exc:`~django.core.exceptions.ValidationError` with a dictionary, where the
keys are the field names. We could update the previous example to assign the
error to the ``pub_date`` field::

    class Article(models.Model):
        ...
        def clean(self):
            # Don't allow draft entries to have a pub_date.
            if self.status == 'draft' and self.pub_date is not None:
                raise ValidationError({'pub_date': 'Draft entries may not have a publication date.'})
            ...

Finally, ``full_clean()`` will check any unique constraints on your model.

.. method:: Model.validate_unique(exclude=None)
+2 −0
Original line number Diff line number Diff line
@@ -381,6 +381,8 @@ class CustomErrorMessage(models.Model):
    def clean(self):
        if self.name1 == 'FORBIDDEN_VALUE':
            raise ValidationError({'name1': [ValidationError('Model.clean() error messages.')]})
        elif self.name1 == 'FORBIDDEN_VALUE2':
            raise ValidationError({'name1': 'Model.clean() error messages (simpler syntax).'})
        elif self.name1 == 'GLOBAL_ERROR':
            raise ValidationError("Global error message.")

+7 −0
Original line number Diff line number Diff line
@@ -2269,6 +2269,13 @@ class ModelFormCustomErrorTests(TestCase):
            str(form.errors['name1']),
            '<ul class="errorlist"><li>Model.clean() error messages.</li></ul>'
        )
        data = {'name1': 'FORBIDDEN_VALUE2', 'name2': 'ABC'}
        form = CustomErrorMessageForm(data)
        self.assertFalse(form.is_valid())
        self.assertHTMLEqual(
            str(form.errors['name1']),
            '<ul class="errorlist"><li>Model.clean() error messages (simpler syntax).</li></ul>'
        )
        data = {'name1': 'GLOBAL_ERROR', 'name2': 'ABC'}
        form = CustomErrorMessageForm(data)
        self.assertFalse(form.is_valid())