summaryrefslogtreecommitdiff
path: root/tests/regressiontests/forms
diff options
context:
space:
mode:
Diffstat (limited to 'tests/regressiontests/forms')
-rw-r--r--tests/regressiontests/forms/formsets.py32
-rw-r--r--tests/regressiontests/forms/regressions.py14
-rw-r--r--tests/regressiontests/forms/tests.py158
3 files changed, 152 insertions, 52 deletions
diff --git a/tests/regressiontests/forms/formsets.py b/tests/regressiontests/forms/formsets.py
index 8d0e3b8d7c..96aa86a9b2 100644
--- a/tests/regressiontests/forms/formsets.py
+++ b/tests/regressiontests/forms/formsets.py
@@ -38,14 +38,14 @@ the COUNT field appropriately.
... }
We treat FormSet pretty much like we would treat a normal Form. FormSet has an
-is_valid method, and a clean_data or errors attribute depending on whether all
-the forms passed validation. However, unlike a Form instance, clean_data and
+is_valid method, and a cleaned_data or errors attribute depending on whether all
+the forms passed validation. However, unlike a Form instance, cleaned_data and
errors will be a list of dicts rather than just a single dict.
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
>>> formset.is_valid()
True
->>> formset.clean_data
+>>> formset.cleaned_data
[{'votes': 100, 'choice': u'Calexico'}]
@@ -64,12 +64,12 @@ False
>>> formset.errors
[{'votes': [u'This field is required.']}]
-Like a Form instance, clean_data won't exist if the formset wasn't validated.
+Like a Form instance, cleaned_data won't exist if the formset wasn't validated.
->>> formset.clean_data
+>>> formset.cleaned_data
Traceback (most recent call last):
...
-AttributeError: 'ChoiceFormSet' object has no attribute 'clean_data'
+AttributeError: 'ChoiceFormSet' object has no attribute 'cleaned_data'
We can also prefill a FormSet with existing data by providing an ``initial``
@@ -99,7 +99,7 @@ Let's simulate what would happen if we submitted this form.
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
>>> formset.is_valid()
True
->>> formset.clean_data
+>>> formset.cleaned_data
[{'votes': 100, 'choice': u'Calexico'}]
But the second form was blank! Shouldn't we get some errors? No. If we display
@@ -176,7 +176,7 @@ number of forms to be completed.
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
>>> formset.is_valid()
True
->>> formset.clean_data
+>>> formset.cleaned_data
[]
@@ -195,7 +195,7 @@ We can just fill out one of the forms.
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
>>> formset.is_valid()
True
->>> formset.clean_data
+>>> formset.cleaned_data
[{'votes': 100, 'choice': u'Calexico'}]
@@ -262,7 +262,7 @@ False
We can easily add deletion ability to a FormSet with an agrument to
formset_for_form. This will add a boolean field to each form instance. When
that boolean field is True, the cleaned data will be in formset.deleted_data
-rather than formset.clean_data
+rather than formset.cleaned_data
>>> ChoiceFormSet = formset_for_form(Choice, deletable=True)
@@ -299,7 +299,7 @@ To delete something, we just need to set that form's special delete field to
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
>>> formset.is_valid()
True
->>> formset.clean_data
+>>> formset.cleaned_data
[{'votes': 100, 'DELETE': False, 'choice': u'Calexico'}]
>>> formset.deleted_data
[{'votes': 900, 'DELETE': True, 'choice': u'Fergie'}]
@@ -308,7 +308,7 @@ True
We can also add ordering ability to a FormSet with an agrument to
formset_for_form. This will add a integer field to each form instance. When
-form validation succeeds, formset.clean_data will have the data in the correct
+form validation succeeds, formset.cleaned_data will have the data in the correct
order specified by the ordering fields. If a number is duplicated in the set
of ordering fields, for instance form 0 and form 3 are both marked as 1, then
the form index used as a secondary ordering criteria. In order to put
@@ -346,8 +346,8 @@ something at the front of the list, you'd need to set it's order to 0.
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
>>> formset.is_valid()
True
->>> for clean_data in formset.clean_data:
-... print clean_data
+>>> for cleaned_data in formset.cleaned_data:
+... print cleaned_data
{'votes': 500, 'ORDER': 0, 'choice': u'The Decemberists'}
{'votes': 100, 'ORDER': 1, 'choice': u'Calexico'}
{'votes': 900, 'ORDER': 2, 'choice': u'Fergie'}
@@ -408,8 +408,8 @@ Let's delete Fergie, and put The Decemberists ahead of Calexico.
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
>>> formset.is_valid()
True
->>> for clean_data in formset.clean_data:
-... print clean_data
+>>> for cleaned_data in formset.cleaned_data:
+... print cleaned_data
{'votes': 500, 'DELETE': False, 'ORDER': 0, 'choice': u'The Decemberists'}
{'votes': 100, 'DELETE': False, 'ORDER': 1, 'choice': u'Calexico'}
>>> formset.deleted_data
diff --git a/tests/regressiontests/forms/regressions.py b/tests/regressiontests/forms/regressions.py
index 5daabc03af..5fe057b5d8 100644
--- a/tests/regressiontests/forms/regressions.py
+++ b/tests/regressiontests/forms/regressions.py
@@ -34,4 +34,18 @@ Unicode decoding problems...
>>> f = SomeForm()
>>> f.as_p()
u'<p><label for="id_somechoice_0">Somechoice:</label> <ul>\n<li><label><input type="radio" id="id_somechoice_0" value="0" name="somechoice" /> En tied\xe4</label></li>\n<li><label><input type="radio" id="id_somechoice_1" value="1" name="somechoice" /> Mies</label></li>\n<li><label><input type="radio" id="id_somechoice_2" value="2" name="somechoice" /> Nainen</label></li>\n</ul></p>'
+
+#######################
+# Miscellaneous Tests #
+#######################
+
+There once was a problem with Form fields called "data". Let's make sure that
+doesn't come back.
+>>> class DataForm(Form):
+... data = CharField(max_length=10)
+>>> f = DataForm({'data': 'xyzzy'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'data': u'xyzzy'}
"""
diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py
index f15034ec66..943cddd1d7 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -1775,7 +1775,7 @@ True
u''
>>> p.errors.as_text()
u''
->>> p.clean_data
+>>> p.cleaned_data
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
>>> print p['first_name']
<input type="text" name="first_name" value="John" id="id_first_name" />
@@ -1811,10 +1811,10 @@ True
{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
>>> p.is_valid()
False
->>> p.clean_data
+>>> p.cleaned_data
Traceback (most recent call last):
...
-AttributeError: 'Person' object has no attribute 'clean_data'
+AttributeError: 'Person' object has no attribute 'cleaned_data'
>>> print p
<tr><th><label for="id_first_name">First name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="first_name" id="id_first_name" /></td></tr>
<tr><th><label for="id_last_name">Last name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="last_name" id="id_last_name" /></td></tr>
@@ -1845,10 +1845,10 @@ False
{}
>>> p.is_valid()
False
->>> p.clean_data
+>>> p.cleaned_data
Traceback (most recent call last):
...
-AttributeError: 'Person' object has no attribute 'clean_data'
+AttributeError: 'Person' object has no attribute 'cleaned_data'
>>> print p
<tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" id="id_first_name" /></td></tr>
<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" id="id_last_name" /></td></tr>
@@ -1887,10 +1887,10 @@ u'<ul class="errorlist"><li>first_name<ul class="errorlist"><li>This field is re
* This field is required.
* birthday
* This field is required.
->>> p.clean_data
+>>> p.cleaned_data
Traceback (most recent call last):
...
-AttributeError: 'Person' object has no attribute 'clean_data'
+AttributeError: 'Person' object has no attribute 'cleaned_data'
>>> p['first_name'].errors
[u'This field is required.']
>>> p['first_name'].errors.as_ul()
@@ -1906,17 +1906,45 @@ u'* This field is required.'
>>> print p['birthday']
<input type="text" name="birthday" id="id_birthday" />
-clean_data will always *only* contain a key for fields defined in the
+cleaned_data will always *only* contain a key for fields defined in the
Form, even if you pass extra data when you define the Form. In this
example, we pass a bunch of extra fields to the form constructor,
-but clean_data contains only the form's fields.
+but cleaned_data contains only the form's fields.
>>> data = {'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9', 'extra1': 'hello', 'extra2': 'hello'}
>>> p = Person(data)
>>> p.is_valid()
True
->>> p.clean_data
+>>> p.cleaned_data
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+cleaned_data will include a key and value for *all* fields defined in the Form,
+even if the Form's data didn't include a value for fields that are not
+required. In this example, the data dictionary doesn't include a value for the
+"nick_name" field, but cleaned_data includes it. For CharFields, it's set to the
+empty string.
+>>> class OptionalPersonForm(Form):
+... first_name = CharField()
+... last_name = CharField()
+... nick_name = CharField(required=False)
+>>> data = {'first_name': u'John', 'last_name': u'Lennon'}
+>>> f = OptionalPersonForm(data)
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'}
+
+For DateFields, it's set to None.
+>>> class OptionalPersonForm(Form):
+... first_name = CharField()
+... last_name = CharField()
+... birth_date = DateField(required=False)
+>>> data = {'first_name': u'John', 'last_name': u'Lennon'}
+>>> f = OptionalPersonForm(data)
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'birth_date': None, 'first_name': u'John', 'last_name': u'Lennon'}
+
"auto_id" tells the Form to add an "id" attribute to each form element.
If it's a string that contains '%s', Django will use that as a format string
into which the field's name will be inserted. It will also put a <label> around
@@ -2265,19 +2293,19 @@ returns a list of input.
>>> f = SongForm({'name': 'Yesterday', 'composers': ['J']}, auto_id=False)
>>> f.errors
{}
->>> f.clean_data
+>>> f.cleaned_data
{'composers': [u'J'], 'name': u'Yesterday'}
>>> f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}, auto_id=False)
>>> f.errors
{}
->>> f.clean_data
+>>> f.cleaned_data
{'composers': [u'J', u'P'], 'name': u'Yesterday'}
Validation errors are HTML-escaped when output as HTML.
>>> class EscapingForm(Form):
... special_name = CharField()
... def clean_special_name(self):
-... raise ValidationError("Something's wrong with '%s'" % self.clean_data['special_name'])
+... raise ValidationError("Something's wrong with '%s'" % self.cleaned_data['special_name'])
>>> f = EscapingForm({'special_name': "Nothing to escape"}, auto_id=False)
>>> print f
@@ -2292,7 +2320,7 @@ 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. In the
-clean_XXX() method, you have access to self.clean_data, which is a dictionary
+clean_XXX() method, you have access to self.cleaned_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):
@@ -2300,9 +2328,9 @@ including the current field (e.g., the field XXX if you're in clean_XXX()).
... password1 = CharField(widget=PasswordInput)
... password2 = CharField(widget=PasswordInput)
... def clean_password2(self):
-... if self.clean_data.get('password1') and self.clean_data.get('password2') and self.clean_data['password1'] != self.clean_data['password2']:
+... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
... raise ValidationError(u'Please make sure your passwords match.')
-... return self.clean_data['password2']
+... return self.cleaned_data['password2']
>>> f = UserRegistration(auto_id=False)
>>> f.errors
{}
@@ -2315,14 +2343,14 @@ including the current field (e.g., the field XXX if you're in clean_XXX()).
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
>>> f.errors
{}
->>> f.clean_data
+>>> f.cleaned_data
{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'}
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 in Form.clean(), you have access to self.clean_data, a dictionary of
+Note that in Form.clean(), you have access to self.cleaned_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):
@@ -2330,9 +2358,9 @@ Form.clean() is required to return a dictionary of all clean data.
... 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']:
+... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
... raise ValidationError(u'Please make sure your passwords match.')
-... return self.clean_data
+... return self.cleaned_data
>>> f = UserRegistration(auto_id=False)
>>> f.errors
{}
@@ -2359,7 +2387,7 @@ Form.clean() is required to return a dictionary of all clean data.
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
>>> f.errors
{}
->>> f.clean_data
+>>> f.cleaned_data
{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'}
# Dynamic construction ########################################################
@@ -2753,6 +2781,64 @@ then the latter will get precedence.
<li>Username: <input type="text" name="username" value="babik" maxlength="10" /></li>
<li>Password: <input type="password" name="password" /></li>
+# Callable initial data ########################################################
+
+The previous technique dealt with raw values as initial data, but it's also
+possible to specify callable data.
+
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10)
+... password = CharField(widget=PasswordInput)
+
+We need to define functions that get called later.
+>>> def initial_django():
+... return 'django'
+>>> def initial_stephane():
+... return 'stephane'
+
+Here, we're not submitting any data, so the initial value will be displayed.
+>>> p = UserRegistration(initial={'username': initial_django}, auto_id=False)
+>>> print p.as_ul()
+<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li>
+<li>Password: <input type="password" name="password" /></li>
+
+The 'initial' parameter is meaningless if you pass data.
+>>> p = UserRegistration({}, initial={'username': initial_django}, auto_id=False)
+>>> print p.as_ul()
+<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
+<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
+>>> p = UserRegistration({'username': u''}, initial={'username': initial_django}, auto_id=False)
+>>> print p.as_ul()
+<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
+<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
+>>> p = UserRegistration({'username': u'foo'}, initial={'username': initial_django}, auto_id=False)
+>>> print p.as_ul()
+<li>Username: <input type="text" name="username" value="foo" maxlength="10" /></li>
+<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
+
+A callable 'initial' value is *not* used as a fallback if data is not provided.
+In this example, we don't provide a value for 'username', and the form raises a
+validation error rather than using the initial value for 'username'.
+>>> p = UserRegistration({'password': 'secret'}, initial={'username': initial_django})
+>>> p.errors
+{'username': [u'This field is required.']}
+>>> p.is_valid()
+False
+
+If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(),
+then the latter will get precedence.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, initial=initial_django)
+... password = CharField(widget=PasswordInput)
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li>
+<li>Password: <input type="password" name="password" /></li>
+>>> p = UserRegistration(initial={'username': initial_stephane}, auto_id=False)
+>>> print p.as_ul()
+<li>Username: <input type="text" name="username" value="stephane" maxlength="10" /></li>
+<li>Password: <input type="password" name="password" /></li>
+
# Help text ###################################################################
You can specify descriptive text for a field by using the 'help_text' argument
@@ -2869,7 +2955,7 @@ actual field name.
{}
>>> p.is_valid()
True
->>> p.clean_data
+>>> p.cleaned_data
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
Let's try submitting some bad data to make sure form.errors and field.errors
@@ -2913,12 +2999,12 @@ of the same form.
>>> p1 = Person(data, prefix='person1')
>>> p1.is_valid()
True
->>> p1.clean_data
+>>> p1.cleaned_data
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
>>> p2 = Person(data, prefix='person2')
>>> p2.is_valid()
True
->>> p2.clean_data
+>>> p2.cleaned_data
{'first_name': u'Jim', 'last_name': u'Morrison', 'birthday': datetime.date(1943, 12, 8)}
By default, forms append a hyphen between the prefix and the field name, but a
@@ -2944,7 +3030,7 @@ self.prefix.
>>> p = Person(data, prefix='foo')
>>> p.is_valid()
True
->>> p.clean_data
+>>> p.cleaned_data
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
# Forms with NullBooleanFields ################################################
@@ -3006,16 +3092,16 @@ is different than its data. This is handled transparently, though.
... 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']:
+... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
... raise ValidationError(u'Please make sure your passwords match.')
-... return self.clean_data
+... return self.cleaned_data
>>> def my_function(method, post_data):
... if method == 'POST':
... form = UserRegistration(post_data, auto_id=False)
... else:
... form = UserRegistration(auto_id=False)
... if form.is_valid():
-... return 'VALID: %r' % form.clean_data
+... return 'VALID: %r' % form.cleaned_data
... t = Template('<form action="" method="post">\n<table>\n{{ form }}\n</table>\n<input type="submit" />\n</form>')
... return t.render(Context({'form': form}))
@@ -3053,9 +3139,9 @@ VALID: {'username': u'adrian', 'password1': u'secret', 'password2': u'secret'}
... 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']:
+... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
... raise ValidationError(u'Please make sure your passwords match.')
-... return self.clean_data
+... return self.cleaned_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
@@ -3321,7 +3407,7 @@ True
</select>
# MultiWidget and MultiValueField #############################################
-# MultiWidgets are widgets composed of other widgets. They are usually
+# MultiWidgets are widgets composed of other widgets. They are usually
# combined with MultiValueFields - a field that is composed of other fields.
# MulitWidgets can themselved be composed of other MultiWidgets.
# SplitDateTimeWidget is one example of a MultiWidget.
@@ -3329,7 +3415,7 @@ True
>>> class ComplexMultiWidget(MultiWidget):
... def __init__(self, attrs=None):
... widgets = (
-... TextInput(),
+... TextInput(),
... SelectMultiple(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))),
... SplitDateTimeWidget(),
... )
@@ -3354,13 +3440,13 @@ True
<input type="text" name="name_2_0" value="2007-04-25" /><input type="text" name="name_2_1" value="06:24:00" />
>>> class ComplexField(MultiValueField):
-... def __init__(self, required=True, widget=None, label=None, initial=None):
+... def __init__(self, required=True, widget=None, label=None, initial=None):
... fields = (
-... CharField(),
+... CharField(),
... MultipleChoiceField(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))),
... SplitDateTimeField()
... )
-... super(ComplexField, self).__init__(fields, required, widget, label, initial)
+... super(ComplexField, self).__init__(fields, required, widget, label, initial)
...
... def compress(self, data_list):
... if data_list:
@@ -3405,7 +3491,7 @@ ValidationError: [u'This field is required.']
</select>
<input type="text" name="field1_2_0" value="2007-04-25" id="id_field1_2_0" /><input type="text" name="field1_2_1" value="06:24:00" id="id_field1_2_1" /></td></tr>
->>> f.clean_data
+>>> f.cleaned_data
{'field1': u'some text,JP,2007-04-25 06:24:00'}
#################################