summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Holovaty <adrian@holovaty.com>2006-11-27 04:49:26 +0000
committerAdrian Holovaty <adrian@holovaty.com>2006-11-27 04:49:26 +0000
commit49236b95e904dbf8560cfb64eb4f5c430ec8f30a (patch)
treef72d7912194c788f72b1737d6446e828458e2707
parent6d36d97cb8d0c982d7481e7d439c9848ded46a77 (diff)
newforms: Added Form.non_field_errors() and added more examples/documentation to the unit tests
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4119 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/newforms/forms.py11
-rw-r--r--tests/regressiontests/forms/tests.py66
2 files changed, 75 insertions, 2 deletions
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.
<tr><td>Field13:</td><td><input type="text" name="field13" /></td></tr>
<tr><td>Field14:</td><td><input type="text" name="field14" /></td></tr>
-# 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 action="">
+... {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
+... {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
+... {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
+... <input type="submit" />
+... </form>''')
+>>> print t.render(Context({'form': UserRegistration()}))
+<form action="">
+<p><label>Your username: <input type="text" name="username" /></label></p>
+<p><label>Password: <input type="password" name="password1" /></label></p>
+<p><label>Password (again): <input type="password" name="password2" /></label></p>
+<input type="submit" />
+</form>
+>>> print t.render(Context({'form': UserRegistration({'username': 'django'})}))
+<form action="">
+<p><label>Your username: <input type="text" name="username" value="django" /></label></p>
+<ul class="errorlist"><li>This field is required.</li></ul><p><label>Password: <input type="password" name="password1" /></label></p>
+<ul class="errorlist"><li>This field is required.</li></ul><p><label>Password (again): <input type="password" name="password2" /></label></p>
+<input type="submit" />
+</form>
+
+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 <ul> (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'})}))
+<form action="">
+<p><label>Your username: <input type="text" name="username" value="django" /></label></p>
+<p><label>Password: <input type="password" name="password1" value="foo" /></label></p>
+<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p>
+<input type="submit" />
+</form>
+>>> t = Template('''<form action="">
+... {{ form.non_field_errors }}
+... {{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
+... {{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
+... {{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
+... <input type="submit" />
+... </form>''')
+>>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'})}))
+<form action="">
+<ul class="errorlist"><li>Please make sure your passwords match.</li></ul>
+<p><label>Your username: <input type="text" name="username" value="django" /></label></p>
+<p><label>Password: <input type="password" name="password1" value="foo" /></label></p>
+<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p>
+<input type="submit" />
+</form>
"""
if __name__ == "__main__":