[Django] #29318: ValidationError has no attribute `error_list` if message is a dict, but Field.run_validators() depends on it

10 views
Skip to first unread message

Django

unread,
Apr 11, 2018, 2:48:14 PM4/11/18
to django-...@googlegroups.com
#29318: ValidationError has no attribute `error_list` if message is a dict, but
Field.run_validators() depends on it
-----------------------------------------+------------------------
Reporter: Michael Käufl | Owner: nobody
Type: Bug | Status: new
Component: Uncategorized | Version: master
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-----------------------------------------+------------------------
If the message is a dict, `ValidationError` has no attribute `error_list`:
{{{
class ValidationError(Exception):

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.

Django

unread,
Apr 11, 2018, 10:32:22 PM4/11/18
to django-...@googlegroups.com
#29318: ValidationError has no attribute `error_list` if message is a dict, but
Field.run_validators() depends on it
-------------------------------+--------------------------------------

Reporter: Michael Käufl | Owner: nobody
Type: Bug | Status: new
Component: Core (Other) | Version: master
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by Tim Graham):

* 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>

Django

unread,
Apr 12, 2018, 3:01:07 AM4/12/18
to django-...@googlegroups.com
#29318: ValidationError has no attribute `error_list` if message is a dict, but
Field.run_validators() depends on it
-------------------------------+--------------------------------------

Reporter: Michael Käufl | Owner: nobody
Type: Bug | Status: new
Component: Core (Other) | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------

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>

Django

unread,
Apr 12, 2018, 9:43:03 AM4/12/18
to django-...@googlegroups.com
#29318: ValidationError has no attribute `error_list` if message is a dict, but
Field.run_validators() depends on it
-------------------------------+--------------------------------------

Reporter: Michael Käufl | Owner: nobody
Type: Bug | Status: new
Component: Core (Other) | Version: master
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------

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>

Django

unread,
Apr 16, 2018, 1:22:06 PM4/16/18
to django-...@googlegroups.com
#29318: ValidationError has no attribute `error_list` if message is a dict, but
Field.run_validators() depends on it
-------------------------------+--------------------------------------

Reporter: Michael Käufl | Owner: nobody
Type: Bug | Status: closed

Component: Core (Other) | Version: master
Severity: Normal | Resolution: wontfix

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+--------------------------------------
Changes (by Tim Graham):

* status: new => closed
* resolution: => wontfix


--
Ticket URL: <https://code.djangoproject.com/ticket/29318#comment:4>

Reply all
Reply to author
Forward
0 new messages