Commit fb1dd6b1 authored by Marc Tamlyn's avatar Marc Tamlyn
Browse files

Form.clean() does not need to return cleaned_data.

If it does, that will be used as the cleaned_data. The default
implementation has been changed to match this change.
parent 7a2296eb
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -297,9 +297,12 @@ class BaseForm(object):

    def _clean_form(self):
        try:
            self.cleaned_data = self.clean()
            cleaned_data = self.clean()
        except ValidationError as e:
            self._errors[NON_FIELD_ERRORS] = self.error_class(e.messages)
        else:
            if cleaned_data is not None:
                self.cleaned_data = cleaned_data

    def _post_clean(self):
        """
@@ -315,7 +318,7 @@ class BaseForm(object):
        not be associated with a particular field; it will have a special-case
        association with the field named '__all__'.
        """
        return self.cleaned_data
        pass

    def has_changed(self):
        """
+2 −10
Original line number Diff line number Diff line
@@ -75,10 +75,8 @@ overridden:
  any validation that requires access to multiple fields from the form at
  once. This is where you might put in things to check that if field ``A``
  is supplied, field ``B`` must contain a valid email address and the
  like. The data that this method returns is the final ``cleaned_data``
  attribute for the form, so don't forget to return the full list of
  cleaned data if you override this method (by default, ``Form.clean()``
  just returns ``self.cleaned_data``).
  like. This method can return a completely different dictionary if it wishes,
  which will be used as the ``cleaned_data``.

  Note that any errors raised by your ``Form.clean()`` override will not
  be associated with any field in particular. They go into a special
@@ -403,9 +401,6 @@ example::
                    raise forms.ValidationError("Did not send for 'help' in "
                            "the subject despite CC'ing yourself.")

            # Always return the full collection of cleaned data.
            return cleaned_data

In this code, if the validation error is raised, the form will display an
error message at the top of the form (normally) describing the problem.

@@ -443,9 +438,6 @@ sample) looks like this::
                del cleaned_data["cc_myself"]
                del cleaned_data["subject"]

            # Always return the full collection of cleaned data.
            return cleaned_data

As you can see, this approach requires a bit more effort, not withstanding the
extra design effort to create a sensible form display. The details are worth
noting, however. Firstly, earlier we mentioned that you might need to check if
+5 −0
Original line number Diff line number Diff line
@@ -127,6 +127,11 @@ Minor features
  for each individual field will be respected, and a new ``incomplete``
  validation error will be raised when any required fields are empty.

* The :meth:`~django.forms.Form.clean` method on a form no longer needs to
  return ``self.cleaned_data``. If it does return a changed dictionary then
  that will still be used. The default implementation no longer returns
  ``self.cleaned_data``.

Backwards incompatible changes in 1.7
=====================================

+18 −0
Original line number Diff line number Diff line
@@ -620,6 +620,24 @@ class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
        self.assertTrue(f.is_valid())
        self.assertEqual(f.cleaned_data['username'], 'sirrobin')

    def test_changing_cleaned_data_in_clean(self):
        class UserForm(Form):
            username = CharField(max_length=10)
            password = CharField(widget=PasswordInput)

            def clean(self):
                data = self.cleaned_data

                # Return a different dict. We have not changed self.cleaned_data.
                return {
                    'username': data['username'].lower(),
                    'password': 'this_is_not_a_secret',
                }

        f = UserForm({'username': 'SirRobin', 'password': 'blue'})
        self.assertTrue(f.is_valid())
        self.assertEqual(f.cleaned_data['username'], 'sirrobin')

    def test_overriding_errorlist(self):
        @python_2_unicode_compatible
        class DivErrorList(ErrorList):