#12960 closed (fixed)
return value (cleaned_data) from clean() method is ignored
Reported by: | krejcik | Owned by: | jkocherhans |
---|---|---|---|
Component: | Forms | Version: | dev |
Severity: | Keywords: | ||
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | yes |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Any changes made by model's clean method are ignored.
Sequence of calls in BaseForm.full_clean() is following:
- _clean_fields - which calls clean on fields and creates instance with cleaned values
- _clean_form - which class clean on model, assign return to form.cleaned_data but instance is not updated
- finally save_instance(construct=False) is called (in previous version of Django model instance was created here from correct cleaned_data)
Attachments (1)
Change History (10)
comment:1 by , 15 years ago
Description: | modified (diff) |
---|---|
Resolution: | → invalid |
Status: | new → closed |
comment:2 by , 15 years ago
Resolution: | invalid |
---|---|
Status: | closed → reopened |
Triage Stage: | Unreviewed → Accepted |
Hey Russ. I actually looked in to this yesterday, but forgot to mark it as accepted. The problem is that the return value of ModelForm.clean()
will never be applied to the model.
comment:3 by , 15 years ago
Here's a quick review the current situation:
- clean form fields
- clean model fields
- clean model
- clean form
The model is cleaned before the form so the model's clean method gets a chance to fix fields before the form's validate_unique method is run.
This puts us into a cyclic problem in where we need to check the model instance before actually being able to clean the form, which may alter the form's cleaned_data. But we need the cleaned_data to accurately build the instance. And we also aren't allowed to call model field's save_form_data more than once (according to other tests).
follow-up: 5 comment:4 by , 15 years ago
Could we fix it by (re)constructing the instance at the end of full_clean()?
follow-up: 6 comment:5 by , 15 years ago
Has patch: | set |
---|---|
Owner: | changed from | to
Patch needs improvement: | set |
Status: | reopened → new |
Replying to patrys:
Could we fix it by (re)constructing the instance at the end of full_clean()?
That's part of a possible solution, but it isn't enough on its own. Model.clean_fields()
and Model.clean()
can modify the model instance in place, so applying all of form.cleaned_data
to the model after that happens could cause different problems.
follow-up: 7 comment:6 by , 15 years ago
Replying to jkocherhans:
That's part of a possible solution, but it isn't enough on its own.
Model.clean_fields()
andModel.clean()
can modify the model instance in place, so applying all ofform.cleaned_data
to the model after that happens could cause different problems.
It shouldn't be possible to do the same thing by either:
- touching
self.instance
- or touching
self.cleaned_data
- or returning a modified copy of
self.cleaned_data
I think self.instance existing at the point when clean()
is called is an implementation detail and is not guaranteed by the API documentation. Modifying the instance directly inside clean()
should be discouraged.
by , 15 years ago
Attachment: | 12960.diff added |
---|
Complete patch. Still thinking about it, but this moves model validation to happen entirely after form validation. I think this is a good thing, but I'm not entirely sure yet.
comment:7 by , 15 years ago
Status: | new → assigned |
---|
Replying to patrys:
I think self.instance existing at the point when
clean()
is called is an implementation detail and is not guaranteed by the API documentation. Modifying the instance directly insideclean()
should be discouraged.
I don't think we can discourage modifying the instance inside Model.clean()
, but for ModelForm.clean()
you're absolutely right. I think my latest patch hits the mark. Instance creation is postponed until after the form validation has completed, then the model validation is run, then unique_validation is run as long as ModelForm.clean()
wasn't overridden without calling super.
Short version:
- clean form fields
- run
form.clean()
- create or update
form.instance
withform.cleaned_data
- clean model fields
- run
instance.clean()
- optionally run
form.validate_unique()
This seems a lot easier to reason about to me. I'd still like Honza to check this out, but I feel pretty good about it at this point. Hopefully I'm not missing some corner case.
comment:8 by , 15 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
Closing invalid because I can't understand what problem you are describing. You seem to be describing some sort of regression with cleaned_data handling, but then you talk about the clean method on a *model*, which suggests you mean model validation.
An example would be extremely helpful. Please reopen if you care to provide sample code, along with usage, and a description of what is happening, what should be happening (and what used to happen if this is actually a regression).