#24706: ModelForm._post_clean assumes that setting attributes onto an instance
cannot raise ValidationError
--------------------------------------+--------------------
Reporter: kezabelle | Owner: nobody
Type: Cleanup/optimization | Status: new
Component: Forms | Version: master
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------------+--------------------
Currently,
[https://github.com/django/django/blob/master/django/forms/models.py#L433
ModelForm._post_clean] calls out to `construct_instance` which, under the
hood, uses `setattr(instance, self.name, data)`, assuming that no
cleverness is taking place, so doesn't attempt to catch `ValidationError`
as subsequent lines do (when calling `full_clean` and `validate_unique`)
This precludes doing things like using `__setattr__` on the model, or
replacing raw attribute access with descriptors (which is
[https://github.com/kezabelle/django-
strictmodels/blob/master/strictmodels.py#L14 what I did] to encounter
this) that do validation checks on assignment rather than remembering to
call `full_clean` everywhere.
As far as I can see, this is the only part of the `_post_clean`
implementation where ValidationError could conceivably be being thrown
which isn't already handled.
Without catching the exception, it I think necessitates using a custom
ModelForm subclass just to do something like:
{{{
class MySubForm(ModelForm):
def _post_clean(self):
try:
super(MySubForm, self)._post_clean()
except ValidationError as e:
self._update_errors(e)
}}}
to avoid the following stacktrace:
{{{
django/forms/forms.py:184: in is_valid
return self.is_bound and not self.errors
django/forms/forms.py:176: in errors
self.full_clean()
django/forms/forms.py:394: in full_clean
self._post_clean()
django/forms/models.py:427: in _post_clean
self.instance = construct_instance(self, self.instance, opts.fields,
construct_instance_exclude)
django/forms/models.py:62: in construct_instance
f.save_form_data(instance, cleaned_data[f.name])
django/db/models/fields/__init__.py:874: in save_form_data
setattr(instance, self.name, data)
strictmodels.py:42: in __set__
new_value = self.field.clean(value=value, model_instance=instance)
django/db/models/fields/__init__.py:589: in clean
self.run_validators(value)
ValidationError: ['error string', 'etc']
}}}
As you can see, the exception is the result of '''my code''', but has
broken the ''implied'' contract of `.is_valid()` being that it suppresses
and collects `ValidationErrors`.
--
Ticket URL: <https://code.djangoproject.com/ticket/24706>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/052.f69cb358bbe737b2572d880c69de685d%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.