#12896 closed (fixed)
ModelForm.is_valid() and ModelForm.errors have backwards-incompatible side effects since model validation
Reported by: | Luke Plant | Owned by: | jkocherhans |
---|---|---|---|
Component: | Forms | Version: | 1.1 |
Severity: | Keywords: | ||
Cc: | Triage Stage: | Design decision needed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Since r12098 (model validation merge), ModelForm.is_valid()
and ModelForm.errors
have the side effect of modifying the bound instance.
Attached is a (rather lazily written) patch to the tests which demonstrates the problem - it ought to pass, and does pass before r12098 (noting that the patch doesn't apply cleanly before r12098), but not after.
This is a significant backwards incompatibility, but rather subtle too - in my case it was caught only due to fairly extensive tests in one of my projects. It is also quite counter-intuitive that either form.errors
or form.is_valid
should have any side effects. At the very least this needs to be clearly documented. I'm guessing it might be tricky to fix, given earlier problems surrounding the order of events in model validation.
For your information, my use case is detecting that a change has occurred to a certain field:
if form.is_valid(): orig_val = obj.val obj = form.save() if obj.val != orig_val: do_something()
The side effects of form.is_valid()
mean that do_something()
is no longer called.
Attachments (1)
Change History (8)
by , 15 years ago
Attachment: | form_is_valid_side_effects_test.diff added |
---|
comment:1 by , 15 years ago
I'm pretty sure this is intended behavior now (it broke one of my projects as well, but it was easily resolved).
comment:2 by , 15 years ago
Component: | Uncategorized → Forms |
---|---|
milestone: | → 1.2 |
Triage Stage: | Unreviewed → Design decision needed |
We need to decide on this one way or the other for 1.2 - if this has changed, we need to make sure the change is intentional.
comment:3 by , 15 years ago
I'm going to think about this more, but I don't see a way around it without extensively altering things or copying the instance. Form.errors
and Form.is_valid()
have had side effects for as long as I can remember, they trigger validation. The side effects are more extensive now, but side effects of those calls in general aren't anything new. I think the solution is just to document it in the backwards compatibility notes, but I'll try to track Honza down at PyCon to chat about it.
comment:4 by , 15 years ago
I'll leave the final call to Joseph, but I think he's right and this should just be noted in the docs.
comment:5 by , 15 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
Model.full_clean()
modifies the model in-place. I hope no one will argue that's the wrong thing to do. So, to fix this I see a couple of solutions, both of which I think are unacceptable.
- Copy the instance. Copying could be an expensive operation, and if the developer really wants to do that, they can just explicitly do it themselves and pass the copy to the
ModeForm
constructor.
- Change the internals of
Model.full_clean()
to optionally not modify the model in place, and changeModelForm
to use that option. I think this option is just needlessly confusing.
I'll add a warning to the release notes and to the ModelForm
docs.
comment:6 by , 15 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
Patch to tests to demonstrate problem.