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('''
+... {{ form.username.errors.as_ul }}

+... {{ form.password1.errors.as_ul }}

+... {{ form.password2.errors.as_ul }}

+... +...
''') +>>> 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