Fixed #12960. The return value of ModelForm.clean() is now applied to the model. Thanks for the report, krejcik.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12690 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Joseph Kocherhans 2010-03-06 18:42:56 +00:00
parent a2c4ad1dab
commit b88f969789
3 changed files with 45 additions and 16 deletions

View File

@ -265,6 +265,7 @@ class BaseForm(StrAndUnicode):
return return
self._clean_fields() self._clean_fields()
self._clean_form() self._clean_form()
self._post_clean()
if self._errors: if self._errors:
delattr(self, 'cleaned_data') delattr(self, 'cleaned_data')
@ -295,6 +296,13 @@ class BaseForm(StrAndUnicode):
except ValidationError, e: except ValidationError, e:
self._errors[NON_FIELD_ERRORS] = self.error_class(e.messages) self._errors[NON_FIELD_ERRORS] = self.error_class(e.messages)
def _post_clean(self):
"""
An internal hook for performing additional cleaning after form cleaning
is complete. Used for model validation in model forms.
"""
pass
def clean(self): def clean(self):
""" """
Hook for doing any extra form-wide cleaning after Field.clean() been Hook for doing any extra form-wide cleaning after Field.clean() been

View File

@ -245,6 +245,10 @@ class BaseModelForm(BaseForm):
# if initial was provided, it should override the values from instance # if initial was provided, it should override the values from instance
if initial is not None: if initial is not None:
object_data.update(initial) object_data.update(initial)
# self._validate_unique will be set to True by BaseModelForm.clean().
# It is False by default so overriding self.clean() and failing to call
# super will stop validate_unique from being called.
self._validate_unique = False
super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data, super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data,
error_class, label_suffix, empty_permitted) error_class, label_suffix, empty_permitted)
@ -299,34 +303,31 @@ class BaseModelForm(BaseForm):
return exclude return exclude
def clean(self): def clean(self):
self.validate_unique() self._validate_unique = True
return self.cleaned_data return self.cleaned_data
def _clean_fields(self): def _post_clean(self):
"""
Cleans the form fields, constructs the instance, then cleans the model
fields.
"""
super(BaseModelForm, self)._clean_fields()
opts = self._meta
self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)
exclude = self._get_validation_exclusions() exclude = self._get_validation_exclusions()
opts = self._meta
# Update the model instance with self.cleaned_data.
self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)
# Clean the model instance's fields.
try: try:
self.instance.clean_fields(exclude=exclude) self.instance.clean_fields(exclude=exclude)
except ValidationError, e: except ValidationError, e:
self._update_errors(e.message_dict) self._update_errors(e.message_dict)
def _clean_form(self): # Call the model instance's clean method.
"""
Runs the instance's clean method, then the form's. This is becuase the
form will run validate_unique() by default, and we should run the
model's clean method first.
"""
try: try:
self.instance.clean() self.instance.clean()
except ValidationError, e: except ValidationError, e:
self._update_errors({NON_FIELD_ERRORS: e.messages}) self._update_errors({NON_FIELD_ERRORS: e.messages})
super(BaseModelForm, self)._clean_form()
# Validate uniqueness if needed.
if self._validate_unique:
self.validate_unique()
def validate_unique(self): def validate_unique(self):
""" """

View File

@ -72,6 +72,26 @@ class OverrideCleanTests(TestCase):
# by form.full_clean(). # by form.full_clean().
self.assertEquals(form.instance.left, 1) self.assertEquals(form.instance.left, 1)
# Regression test for #12960.
# Make sure the cleaned_data returned from ModelForm.clean() is applied to the
# model instance.
class PublicationForm(forms.ModelForm):
def clean(self):
print self.cleaned_data
self.cleaned_data['title'] = self.cleaned_data['title'].upper()
return self.cleaned_data
class Meta:
model = Publication
class ModelFormCleanTest(TestCase):
def test_model_form_clean_applies_to_model(self):
data = {'title': 'test', 'date_published': '2010-2-25'}
form = PublicationForm(data)
publication = form.save()
self.assertEqual(publication.title, 'TEST')
class FPForm(forms.ModelForm): class FPForm(forms.ModelForm):
class Meta: class Meta:
model = FilePathModel model = FilePathModel