diff --git a/django/newforms/forms.py b/django/newforms/forms.py
index a07df84e54..667ae0a472 100644
--- a/django/newforms/forms.py
+++ b/django/newforms/forms.py
@@ -99,6 +99,13 @@ class Form(object):
output.append(line)
return u'\n'.join(output)
+ def non_field_errors(self):
+ """
+ Returns a list of errors that aren't associated with a particular
+ field -- i.e., from Form.clean().
+ """
+ return self.errors.get(NON_FIELD_ERRORS, [])
+
def full_clean(self):
"""
Cleans all of self.data and populates self.__errors and self.clean_data.
@@ -129,7 +136,9 @@ class Form(object):
def clean(self):
"""
Hook for doing any extra form-wide cleaning after Field.clean() been
- called on every field.
+ called on every field. Any ValidationError raised by this method will
+ not be associated with a particular field; it will have a special-case
+ association with the field named '__all__'.
"""
return self.clean_data
diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py
index 8de27dee51..c7e222c7d2 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -1520,7 +1520,7 @@ A Form's fields are displayed in the same order in which they were defined.
Field13:
Field14:
-# Sample form processing (as if in a view) ####################################
+# Basic form processing in a view #############################################
>>> from django.template import Template, Context
>>> class UserRegistration(Form):
@@ -1568,6 +1568,70 @@ Case 2: POST with erroneous data (a redisplayed form, with errors).
Case 3: POST with valid data (the success message).
>>> print my_function('POST', {'username': 'adrian', 'password1': 'secret', 'password2': 'secret'})
VALID
+
+# Some ideas for using templates with forms ###################################
+
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10)
+... password1 = CharField(widget=PasswordInput)
+... password2 = CharField(widget=PasswordInput)
+... def clean(self):
+... if self.clean_data.get('password1') and self.clean_data.get('password2') and self.clean_data['password1'] != self.clean_data['password2']:
+... raise ValidationError(u'Please make sure your passwords match.')
+... return self.clean_data
+
+You have full flexibility in displaying form fields in a template. Just pass a
+Form instance to the template, and use "dot" access to refer to individual
+fields. Note, however, that this flexibility comes with the responsibility of
+displaying all the errors, including any that might not be associated with a
+particular field.
+>>> t = Template('''''')
+>>> print t.render(Context({'form': UserRegistration()}))
+
+>>> print t.render(Context({'form': UserRegistration({'username': 'django'})}))
+
+
+To display the errors that aren't associated with a particular field -- e.g.,
+the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the
+template. If used on its own, it is displayed as a
(or an empty string, if
+the list of errors is empty). You can also use it in {% if %} statements.
+>>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'})}))
+
+>>> t = Template('''''')
+>>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'})}))
+
"""
if __name__ == "__main__":