#14234 closed (fixed)
Validation bug when using ModelForms
Reported by: | David Reynolds | Owned by: | Jeremy Dunck |
---|---|---|---|
Component: | Forms | Version: | 1.2 |
Severity: | Keywords: | ||
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I am running into a validation problem with ModelForms - here is a quick summary of what is happening
Take a simple model - here we call Model
.full_clean
as part of the custom save method to enforce the validation:
from django.db import models class Stuff(models.Model): """(Stuff description)""" name = models.CharField(max_length=100) age = models.IntegerField() description = models.TextField(blank=True) def __unicode__(self): return self.name def save(self, *args, **kwargs): self.full_clean() return super(Stuff, self).save(*args, **kwargs)
Simple ModelForm for the above - nothing unusual here:
from django import forms class StuffModelForm(forms.ModelForm): class Meta: model = Stuff # Instantiate the form with some data form = StuffModelForm({ 'name': 'Fred', 'age': '56', 'description': 'Old Fred is 57', }) # Check the form is valid if form.is_valid(): obj = form.save(commit=False) # save but don't commit obj.age = 27 # Change the age obj.save() # Do a full save of the object obj.name = 'Ted' # Change the name obj.save() # Attempt to update the db record # you get this error: ValidationError: {'id': [u'Stuff with this ID already exists.']}
This happens because the ModelForm
sets ModelForm
.instance
._adding
to True
and never cleans it up. This is then tested for in Model
._perform_unique_checks
and the uniqueness checks are executed if it is set to True
which it always is after calling ModelForm
.save
()
Attachments (3)
Change History (10)
comment:1 by , 14 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
by , 14 years ago
Attachment: | dj14234-signal.diff added |
---|
comment:2 by , 14 years ago
Has patch: | set |
---|---|
Needs tests: | set |
Patch needs improvement: | set |
Set flags I missed.
comment:3 by , 14 years ago
Has patch: | unset |
---|---|
Needs tests: | unset |
Patch needs improvement: | unset |
Jeremy, it seemed massively overkill to use a signal for this, so I went with the simpler version and added a test for it.
comment:4 by , 14 years ago
Triage Stage: | Unreviewed → Accepted |
---|
Given that a core committer proposed a patch, I'm assuming this should be flagged as "Accepted"
comment:5 by , 14 years ago
Has patch: | set |
---|
I'm not a core committer - just a long-time contributor. Even so, yes, I think this is ready for review.
comment:6 by , 14 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
Though I am not sure putting full_clean in a model's .save is a good approach, I do agree with your assessment of the bug - that _adding should be reset.
Given that _adding is only set by BaseModelForm, I think it should be responsible for cleaning it up. That would suggest using a signal on post_save from BaseModelForm. Unfortunately, that's bad for performance since it means a lot of housekeeping, and maybe some apps have many active forms.
A slightly hackier way, but less code and definitely faster, would be just having Model.save_base reset ._adding.
I've attached (untested) patches for both. I'd lean toward the fast/hacky way, but if it works for you, please add tests so it can be committed.