From 126e0ec0c3096ae5c631b00b29ff9e9f01ca15c2 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Mon, 27 Nov 2006 03:49:19 +0000 Subject: Fixed #3026 -- newforms: Form class now suppresses validation and errors if no data (or None) is passed in. Validation still happens if you pass in an empty dictionary. Also updated unit tests. Thanks, SmileyChris git-svn-id: http://code.djangoproject.com/svn/django/trunk@4117 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- tests/regressiontests/forms/tests.py | 152 +++++++++++++++++++++++++++-------- 1 file changed, 117 insertions(+), 35 deletions(-) (limited to 'tests') diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 3d7543badd..8de27dee51 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -1137,31 +1137,8 @@ u'' ... first_name = CharField() ... last_name = CharField() ... birthday = DateField() ->>> p = Person() ->>> print p -First name: -Last name: -Birthday: ->>> print p.as_table() -First name: -Last name: -Birthday: ->>> print p.as_ul() -
  • First name:
  • -
  • Last name:
  • -
  • Birthday:
  • ->>> print p.as_table_with_errors() - -First name: - -Last name: - -Birthday: ->>> print p.as_ul_with_errors() -
  • First name:
  • -
  • Last name:
  • -
  • Birthday:
  • +Pass a dictionary to a Form's __init__(). >>> p = Person({'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9'}) >>> p.errors {} @@ -1189,12 +1166,58 @@ u'' Last name: Birthday: +Empty dictionaries are valid, too. +>>> p = Person({}) +>>> p.errors +{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']} +>>> p.is_valid() +False +>>> print p + +First name: + +Last name: + +Birthday: +>>> print p.as_table() + +First name: + +Last name: + +Birthday: +>>> print p.as_ul() +
  • First name:
  • +
  • Last name:
  • +
  • Birthday:
  • + +If you don't pass any values to the Form's __init__(), or if you pass None, +the Form won't do any validation. Form.errors will be an empty dictionary *but* +Form.is_valid() will return False. +>>> p = Person() +>>> p.errors +{} +>>> p.is_valid() +False +>>> print p +First name: +Last name: +Birthday: +>>> print p.as_table() +First name: +Last name: +Birthday: +>>> print p.as_ul() +
  • First name:
  • +
  • Last name:
  • +
  • Birthday:
  • + Unicode values are handled properly. ->>> p = Person({'first_name': u'John', 'last_name': u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'}) +>>> p = Person({'first_name': u'John', 'last_name': u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111', 'birthday': '1940-10-9'}) >>> p.as_table() -u'First name:\nLast name:\nBirthday:' +u'First name:\nLast name:\nBirthday:' >>> p.as_ul() -u'
  • First name:
  • \n
  • Last name:
  • \n
  • Birthday:
  • ' +u'
  • First name:
  • \n
  • Last name:
  • \n
  • Birthday:
  • ' >>> p = Person({'last_name': u'Lennon'}) >>> p.errors @@ -1375,7 +1398,10 @@ MultipleChoiceField is a special case, as its data is required to be a list: There are a couple of ways to do multiple-field validation. If you want the validation message to be associated with a particular field, implement the clean_XXX() method on the Form, where XXX is the field name. As in -Field.clean(), the clean_XXX() method should return the cleaned value: +Field.clean(), the clean_XXX() method should return the cleaned value. In the +clean_XXX() method, you have access to self.clean_data, which is a dictionary +of all the data that has been cleaned *so far*, in order by the fields, +including the current field (e.g., the field XXX if you're in clean_XXX()). >>> class UserRegistration(Form): ... username = CharField(max_length=10) ... password1 = CharField(widget=PasswordInput) @@ -1386,6 +1412,9 @@ Field.clean(), the clean_XXX() method should return the cleaned value: ... return self.clean_data['password2'] >>> f = UserRegistration() >>> f.errors +{} +>>> f = UserRegistration({}) +>>> f.errors {'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']} >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}) >>> f.errors @@ -1399,8 +1428,10 @@ Field.clean(), the clean_XXX() method should return the cleaned value: Another way of doing multiple-field validation is by implementing the Form's clean() method. If you do this, any ValidationError raised by that method will not be associated with a particular field; it will have a -special-case association with the field named '__all__'. Note that -Form.clean() still needs to return a dictionary of all clean data: +special-case association with the field named '__all__'. +Note that in Form.clean(), you have access to self.clean_data, a dictionary of +all the fields/values that have *not* raised a ValidationError. Also note +Form.clean() is required to return a dictionary of all clean data. >>> class UserRegistration(Form): ... username = CharField(max_length=10) ... password1 = CharField(widget=PasswordInput) @@ -1410,9 +1441,15 @@ Form.clean() still needs to return a dictionary of all clean data: ... raise ValidationError(u'Please make sure your passwords match.') ... return self.clean_data >>> f = UserRegistration() +>>> f.errors +{} +>>> f = UserRegistration({}) >>> print f.as_table() + Username: + Password1: + Password2: >>> f.errors {'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']} @@ -1420,15 +1457,11 @@ Form.clean() still needs to return a dictionary of all clean data: >>> f.errors {'__all__': [u'Please make sure your passwords match.']} >>> print f.as_table() -Username: -Password1: -Password2: ->>> print f.as_table_with_errors() Username: Password1: Password2: ->>> print f.as_ul_with_errors() +>>> print f.as_ul()
  • Username:
  • Password1:
  • @@ -1486,6 +1519,55 @@ A Form's fields are displayed in the same order in which they were defined. Field12: Field13: Field14: + +# Sample form processing (as if in a view) #################################### + +>>> from django.template import Template, Context +>>> 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 +>>> def my_function(method, post_data): +... if method == 'POST': +... form = UserRegistration(post_data) +... else: +... form = UserRegistration() +... if form.is_valid(): +... return 'VALID' +... t = Template('
    \n\n{{ form }}\n
    \n\n
    ') +... return t.render(Context({'form': form})) + +Case 1: GET (an empty form, with no errors). +>>> print my_function('GET', {}) +
    + + + + +
    Username:
    Password1:
    Password2:
    + +
    + +Case 2: POST with erroneous data (a redisplayed form, with errors). +>>> print my_function('POST', {'username': 'this-is-a-long-username', 'password1': 'foo', 'password2': 'bar'}) +
    + + + + + + +
    • Please make sure your passwords match.
    • Ensure this value has at most 10 characters.
    Username:
    Password1:
    Password2:
    + +
    + +Case 3: POST with valid data (the success message). +>>> print my_function('POST', {'username': 'adrian', 'password1': 'secret', 'password2': 'secret'}) +VALID """ if __name__ == "__main__": -- cgit v1.3