Ticket #12596: 12596_r12222.diff

File 12596_r12222.diff, 4.9 KB (added by Carl Meyer, 14 years ago)
  • django/forms/forms.py

    diff --git a/django/forms/forms.py b/django/forms/forms.py
    a b  
    253253    def full_clean(self):
    254254        """
    255255        Cleans all of self.data and populates self._errors and
    256         self.cleaned_data.
     256        self.cleaned_data. Returns True if validation was performed,
     257        False otherwise.
    257258        """
    258259        self._errors = ErrorDict()
    259260        if not self.is_bound: # Stop further processing.
    260             return
     261            return False
    261262        self.cleaned_data = {}
    262263        # If the form is permitted to be empty, and none of the form data has
    263264        # changed from the initial data, short circuit any validation.
    264265        if self.empty_permitted and not self.has_changed():
    265             return
     266            return False
    266267        for name, field in self.fields.items():
    267268            # value_from_datadict() gets the data from the data dictionaries.
    268269            # Each widget type knows how to retrieve its own data, because some
     
    288289            self._errors[NON_FIELD_ERRORS] = self.error_class(e.messages)
    289290        if self._errors:
    290291            delattr(self, 'cleaned_data')
     292        return True
    291293
    292294    def clean(self):
    293295        """
  • django/forms/models.py

    diff --git a/django/forms/models.py b/django/forms/models.py
    a b  
    280280                    exclude.append(f.name)
    281281        return exclude
    282282
    283     def clean(self):
     283    def full_clean(self):
     284        needs_validation = super(BaseModelForm, self).full_clean()
     285        if needs_validation:
     286            self.clean_instance()
     287        return needs_validation
     288
     289    def clean_instance(self):
     290        if not hasattr(self, 'cleaned_data'):
     291            self.cleaned_data = {}
    284292        opts = self._meta
    285293        self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)
    286294        exclude = self._get_validation_exclusions()
     
    288296            self.instance.full_clean(exclude=exclude)
    289297        except ValidationError, e:
    290298            for k, v in e.message_dict.items():
    291                 if k != NON_FIELD_ERRORS:
    292                     self._errors.setdefault(k, ErrorList()).extend(v)
    293                     # Remove the data from the cleaned_data dict since it was invalid
    294                     if k in self.cleaned_data:
    295                         del self.cleaned_data[k]
    296             if NON_FIELD_ERRORS in e.message_dict:
    297                 raise ValidationError(e.message_dict[NON_FIELD_ERRORS])
    298         return self.cleaned_data
     299                self._errors.setdefault(k, ErrorList()).extend(v)
     300        if self._errors:
     301            delattr(self, 'cleaned_data')
    299302
    300303    def save(self, commit=True):
    301304        """
  • docs/topics/forms/modelforms.txt

    diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt
    a b  
    464464You can override the ``clean()`` method on a model form to provide additional
    465465validation in the same way you can on a normal form.
    466466
    467 In this regard, model forms have two specific characteristics when compared to
    468 forms:
    469 
    470 By default the ``clean()`` method validates the uniqueness of fields that are
    471 marked as ``unique``, ``unique_together`` or ``unique_for_date|month|year`` on
    472 the model.  Therefore, if you would like to override the ``clean()`` method and
    473 maintain the default validation, you must call the parent class's ``clean()``
    474 method.
    475 
    476467Also, a model form instance bound to a model object will contain a
    477468``self.instance`` attribute that gives model form methods access to that
    478469specific model instance.
  • tests/regressiontests/model_forms_regress/tests.py

    diff --git a/tests/regressiontests/model_forms_regress/tests.py b/tests/regressiontests/model_forms_regress/tests.py
    a b  
    5050        form = TripleForm({'left': '1', 'middle': '3', 'right': '1'})
    5151        self.failUnless(form.is_valid())
    5252
     53
     54class TripleFormWithCleanOverride(forms.ModelForm):
     55    class Meta:
     56        model = Triple
     57
     58    def clean(self):
     59        if not self.cleaned_data['left'] == self.cleaned_data['right']:
     60            raise forms.ValidationError('Left and right should be equal')
     61        return self.cleaned_data
     62
     63class OverrideCleanTests(TestCase):
     64    def test_override_clean(self):
     65        """
     66        Regression for #12596: ModelForm.clean() should be optional.
     67
     68        """
     69        form = TripleFormWithCleanOverride({'left': 1, 'middle': 2, 'right': 1})
     70        self.failUnless(form.is_valid())
     71        self.assertEquals(form.instance.left, 1,
     72                          'form.instance not set up by form.is_valid()')
     73
     74
    5375class FPForm(forms.ModelForm):
    5476    class Meta:
    5577        model = FilePathModel
     
    113135            date_published=date(1991, 8, 22))
    114136        f = Form()
    115137        self.assertEqual(len(f.fields["publications"].choices), 1)
     138
Back to Top