Skip to content


Subversion checkout URL

You can clone with
Download ZIP
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.
  • Loading branch information...
commit fb1dd6b13a0e6b1ef64eac88467321d097942cd2 1 parent 7a2296e
@mjtamlyn mjtamlyn authored
7 django/forms/
@@ -297,9 +297,12 @@ def _clean_fields(self):
def _clean_form(self):
- 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 @@ def clean(self):
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):
12 docs/ref/forms/validation.txt
@@ -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 docs/releases/1.7.txt
@@ -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 tests/forms_tests/tests/
@@ -620,6 +620,24 @@ def clean(self):
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):
class DivErrorList(ErrorList):
Please sign in to comment.
Something went wrong with that request. Please try again.