def __init__(self, message, code=None, params=None):
# …
if isinstance(message, dict): # <----
self.error_dict = {}
for field, messages in message.items():
if not isinstance(messages, ValidationError):
messages = ValidationError(messages)
self.error_dict[field] = messages.error_list
elif isinstance(message, list):
self.error_list = …
# …
else:
# …
self.error_list = [self]
}}}
See
-
https://github.com/django/django/blob/2.0.4/django/core/exceptions.py#L115-L137
-
https://github.com/django/django/blob/c3055242c81812278ebdc93dd109f30d2cbd1610/django/core/exceptions.py#L115-L137
(current master)
But `Field.run_validators()` depends on `ValidationError` having an
attribute `error_list`:
{{{
class Field(RegisterLookupMixin):
def run_validators(self, value):
# …
for v in self.validators:
try:
v(value)
except exceptions.ValidationError as e:
if hasattr(e, 'code') and e.code in self.error_messages:
e.message = self.error_messages[e.code]
errors.extend(e.error_list) # <----
# …
}}}
See
-
https://github.com/django/django/blob/2.0.4/django/db/models/fields/__init__.py#L553-L567
-
https://github.com/django/django/blob/c3055242c81812278ebdc93dd109f30d2cbd1610/django/db/models/fields/__init__.py#L577-L591
(current master)
This leads to an `AttributeError` when using a dict as message when
raising a `ValidationError` inside a validator.
--
Ticket URL: <https://code.djangoproject.com/ticket/29318>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* component: Uncategorized => Core (Other)
Comment:
Could you elaborate on the use case for using a dictionary message inside
a validator's `ValidationError`? I would expect validators to be generic
and not know the field names they are being used with.
--
Ticket URL: <https://code.djangoproject.com/ticket/29318#comment:1>
Comment (by Michael Käufl):
Sure. Consider a JSONField with an allowed list of keys:
{{{
if key not in allowed_keys:
raise ValidationError({key: 'Not allowed.'})
}}}
We use these exceptions not only for the admin, but also for API error
messages through django rest framework's [http://www.django-rest-
framework.org/api-guide/exceptions/#custom-exception-handling custom
exception handling]. This is also the reason, why we use the field's name
in some other (therefore non-generic) validators. Using the field's name
as key in the error_dict, allows our front-end to display the error
message at the affected field and not as a generic error message of the
form.
--
Ticket URL: <https://code.djangoproject.com/ticket/29318#comment:2>
Comment (by Simon Charette):
I think that `Field.run_validators()` should not to handle `dict` based
`ValidationError` as they should only be used to map concrete fields to
errors in multi-fields cleaning functions (e.g. `Form.clean()`,
`Model.clean()`). Since `Field` instances cannot have nested-fields I
wouldn't expect `dict` to be handled.
In your `JSONField` subclass example you're using an invalid `key` as your
field mapping. This `key` doesn't map to any field and raising
`ValidationError(f'Key {key} not allowed.')` within the field would be
more appropriate.
Keep in mind that errors have to be ultimately flattened to a `{field_name
-> error_list}` map at the form/model level while a different model is
used for DRF serializers since they have nested fields.
--
Ticket URL: <https://code.djangoproject.com/ticket/29318#comment:3>
* status: new => closed
* resolution: => wontfix
--
Ticket URL: <https://code.djangoproject.com/ticket/29318#comment:4>