~ubuntu-branches/ubuntu/oneiric/python-django/oneiric

« back to all changes in this revision

Viewing changes to tests/regressiontests/forms/tests/forms.py

  • Committer: Bazaar Package Importer
  • Author(s): Jamie Strandboge
  • Date: 2011-02-17 13:34:07 UTC
  • mfrom: (1.1.13 upstream) (4.4.12 sid)
  • Revision ID: james.westby@ubuntu.com-20110217133407-rwr88elhhq6j7ba0
Tags: 1.2.5-1ubuntu1
* Merge from Debian for security fixes (LP: #719031). Remaining changes:
  - debian/control: don't Build-Depends on locales-all, which doesn't exist
    in natty
* Drop the following patches, now included upstream:
  - debian/patches/07_security_admin_infoleak.diff
  - debian/patches/08_security_pasword_reset_dos.diff

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
import datetime
 
3
from decimal import Decimal
 
4
import re
 
5
import time
 
6
from unittest import TestCase
 
7
from django.core.files.uploadedfile import SimpleUploadedFile
 
8
from django.forms import *
 
9
from django.http import QueryDict
 
10
from django.template import Template, Context
 
11
from django.utils.datastructures import MultiValueDict, MergeDict
 
12
from django.utils.safestring import mark_safe
 
13
 
 
14
 
 
15
class Person(Form):
 
16
    first_name = CharField()
 
17
    last_name = CharField()
 
18
    birthday = DateField()
 
19
 
 
20
 
 
21
class PersonNew(Form):
 
22
    first_name = CharField(widget=TextInput(attrs={'id': 'first_name_id'}))
 
23
    last_name = CharField()
 
24
    birthday = DateField()
 
25
 
 
26
 
 
27
class FormsTestCase(TestCase):
 
28
    # A Form is a collection of Fields. It knows how to validate a set of data and it
 
29
    # knows how to render itself in a couple of default ways (e.g., an HTML table).
 
30
    # You can pass it data in __init__(), as a dictionary.
 
31
 
 
32
    def test_form(self):
 
33
        # Pass a dictionary to a Form's __init__().
 
34
        p = Person({'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9'})
 
35
 
 
36
        self.assertTrue(p.is_bound)
 
37
        self.assertEqual(p.errors, {})
 
38
        self.assertTrue(p.is_valid())
 
39
        self.assertEqual(p.errors.as_ul(), u'')
 
40
        self.assertEqual(p.errors.as_text(), u'')
 
41
        self.assertEqual(p.cleaned_data["first_name"], u'John')
 
42
        self.assertEqual(p.cleaned_data["last_name"], u'Lennon')
 
43
        self.assertEqual(p.cleaned_data["birthday"], datetime.date(1940, 10, 9))
 
44
        self.assertEqual(str(p['first_name']), '<input type="text" name="first_name" value="John" id="id_first_name" />')
 
45
        self.assertEqual(str(p['last_name']), '<input type="text" name="last_name" value="Lennon" id="id_last_name" />')
 
46
        self.assertEqual(str(p['birthday']), '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" />')
 
47
        try:
 
48
            p['nonexistentfield']
 
49
            self.fail('Attempts to access non-existent fields should fail.')
 
50
        except KeyError:
 
51
            pass
 
52
 
 
53
        form_output = []
 
54
 
 
55
        for boundfield in p:
 
56
            form_output.append(str(boundfield))
 
57
 
 
58
        self.assertEqual('\n'.join(form_output), """<input type="text" name="first_name" value="John" id="id_first_name" />
 
59
<input type="text" name="last_name" value="Lennon" id="id_last_name" />
 
60
<input type="text" name="birthday" value="1940-10-9" id="id_birthday" />""")
 
61
 
 
62
        form_output = []
 
63
 
 
64
        for boundfield in p:
 
65
            form_output.append([boundfield.label, boundfield.data])
 
66
 
 
67
        self.assertEqual(form_output, [
 
68
            ['First name', u'John'],
 
69
            ['Last name', u'Lennon'],
 
70
            ['Birthday', u'1940-10-9']
 
71
        ])
 
72
        self.assertEqual(str(p), """<tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" value="John" id="id_first_name" /></td></tr>
 
73
<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" value="Lennon" id="id_last_name" /></td></tr>
 
74
<tr><th><label for="id_birthday">Birthday:</label></th><td><input type="text" name="birthday" value="1940-10-9" id="id_birthday" /></td></tr>""")
 
75
 
 
76
    def test_empty_dict(self):
 
77
        # Empty dictionaries are valid, too.
 
78
        p = Person({})
 
79
        self.assertTrue(p.is_bound)
 
80
        self.assertEqual(p.errors['first_name'], [u'This field is required.'])
 
81
        self.assertEqual(p.errors['last_name'], [u'This field is required.'])
 
82
        self.assertEqual(p.errors['birthday'], [u'This field is required.'])
 
83
        self.assertFalse(p.is_valid())
 
84
        try:
 
85
            p.cleaned_data
 
86
            self.fail('Attempts to access cleaned_data when validation fails should fail.')
 
87
        except AttributeError:
 
88
            pass
 
89
        self.assertEqual(str(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>
 
90
<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>
 
91
<tr><th><label for="id_birthday">Birthday:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="birthday" id="id_birthday" /></td></tr>""")
 
92
        self.assertEqual(p.as_table(), """<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>
 
93
<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>
 
94
<tr><th><label for="id_birthday">Birthday:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="birthday" id="id_birthday" /></td></tr>""")
 
95
        self.assertEqual(p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li>
 
96
<li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li>
 
97
<li><ul class="errorlist"><li>This field is required.</li></ul><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></li>""")
 
98
        self.assertEqual(p.as_p(), """<ul class="errorlist"><li>This field is required.</li></ul>
 
99
<p><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></p>
 
100
<ul class="errorlist"><li>This field is required.</li></ul>
 
101
<p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></p>
 
102
<ul class="errorlist"><li>This field is required.</li></ul>
 
103
<p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></p>""")
 
104
 
 
105
    def test_unbound_form(self):
 
106
        # If you don't pass any values to the Form's __init__(), or if you pass None,
 
107
        # the Form will be considered unbound and won't do any validation. Form.errors
 
108
        # will be an empty dictionary *but* Form.is_valid() will return False.
 
109
        p = Person()
 
110
        self.assertFalse(p.is_bound)
 
111
        self.assertEqual(p.errors, {})
 
112
        self.assertFalse(p.is_valid())
 
113
        try:
 
114
            p.cleaned_data
 
115
            self.fail('Attempts to access cleaned_data when validation fails should fail.')
 
116
        except AttributeError:
 
117
            pass
 
118
        self.assertEqual(str(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>
 
119
<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" id="id_last_name" /></td></tr>
 
120
<tr><th><label for="id_birthday">Birthday:</label></th><td><input type="text" name="birthday" id="id_birthday" /></td></tr>""")
 
121
        self.assertEqual(p.as_table(), """<tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" id="id_first_name" /></td></tr>
 
122
<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" id="id_last_name" /></td></tr>
 
123
<tr><th><label for="id_birthday">Birthday:</label></th><td><input type="text" name="birthday" id="id_birthday" /></td></tr>""")
 
124
        self.assertEqual(p.as_ul(), """<li><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li>
 
125
<li><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li>
 
126
<li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></li>""")
 
127
        self.assertEqual(p.as_p(), """<p><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></p>
 
128
<p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></p>
 
129
<p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /></p>""")
 
130
 
 
131
    def test_unicode_values(self):
 
132
        # Unicode values are handled properly.
 
133
        p = Person({'first_name': u'John', 'last_name': u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111', 'birthday': '1940-10-9'})
 
134
        self.assertEqual(p.as_table(), u'<tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" value="John" id="id_first_name" /></td></tr>\n<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" id="id_last_name" /></td></tr>\n<tr><th><label for="id_birthday">Birthday:</label></th><td><input type="text" name="birthday" value="1940-10-9" id="id_birthday" /></td></tr>')
 
135
        self.assertEqual(p.as_ul(), u'<li><label for="id_first_name">First name:</label> <input type="text" name="first_name" value="John" id="id_first_name" /></li>\n<li><label for="id_last_name">Last name:</label> <input type="text" name="last_name" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" id="id_last_name" /></li>\n<li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" value="1940-10-9" id="id_birthday" /></li>')
 
136
        self.assertEqual(p.as_p(), u'<p><label for="id_first_name">First name:</label> <input type="text" name="first_name" value="John" id="id_first_name" /></p>\n<p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" id="id_last_name" /></p>\n<p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" value="1940-10-9" id="id_birthday" /></p>')
 
137
 
 
138
        p = Person({'last_name': u'Lennon'})
 
139
        self.assertEqual(p.errors['first_name'], [u'This field is required.'])
 
140
        self.assertEqual(p.errors['birthday'], [u'This field is required.'])
 
141
        self.assertFalse(p.is_valid())
 
142
        self.assertEqual(p.errors.as_ul(), u'<ul class="errorlist"><li>first_name<ul class="errorlist"><li>This field is required.</li></ul></li><li>birthday<ul class="errorlist"><li>This field is required.</li></ul></li></ul>')
 
143
        self.assertEqual(p.errors.as_text(), """* first_name
 
144
  * This field is required.
 
145
* birthday
 
146
  * This field is required.""")
 
147
        try:
 
148
            p.cleaned_data
 
149
            self.fail('Attempts to access cleaned_data when validation fails should fail.')
 
150
        except AttributeError:
 
151
            pass
 
152
        self.assertEqual(p['first_name'].errors, [u'This field is required.'])
 
153
        self.assertEqual(p['first_name'].errors.as_ul(), u'<ul class="errorlist"><li>This field is required.</li></ul>')
 
154
        self.assertEqual(p['first_name'].errors.as_text(), u'* This field is required.')
 
155
 
 
156
        p = Person()
 
157
        self.assertEqual(str(p['first_name']), '<input type="text" name="first_name" id="id_first_name" />')
 
158
        self.assertEqual(str(p['last_name']), '<input type="text" name="last_name" id="id_last_name" />')
 
159
        self.assertEqual(str(p['birthday']), '<input type="text" name="birthday" id="id_birthday" />')
 
160
 
 
161
    def test_cleaned_data_only_fields(self):
 
162
        # cleaned_data will always *only* contain a key for fields defined in the
 
163
        # Form, even if you pass extra data when you define the Form. In this
 
164
        # example, we pass a bunch of extra fields to the form constructor,
 
165
        # but cleaned_data contains only the form's fields.
 
166
        data = {'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9', 'extra1': 'hello', 'extra2': 'hello'}
 
167
        p = Person(data)
 
168
        self.assertTrue(p.is_valid())
 
169
        self.assertEqual(p.cleaned_data['first_name'], u'John')
 
170
        self.assertEqual(p.cleaned_data['last_name'], u'Lennon')
 
171
        self.assertEqual(p.cleaned_data['birthday'], datetime.date(1940, 10, 9))
 
172
 
 
173
    def test_optional_data(self):
 
174
        # cleaned_data will include a key and value for *all* fields defined in the Form,
 
175
        # even if the Form's data didn't include a value for fields that are not
 
176
        # required. In this example, the data dictionary doesn't include a value for the
 
177
        # "nick_name" field, but cleaned_data includes it. For CharFields, it's set to the
 
178
        # empty string.
 
179
        class OptionalPersonForm(Form):
 
180
            first_name = CharField()
 
181
            last_name = CharField()
 
182
            nick_name = CharField(required=False)
 
183
 
 
184
        data = {'first_name': u'John', 'last_name': u'Lennon'}
 
185
        f = OptionalPersonForm(data)
 
186
        self.assertTrue(f.is_valid())
 
187
        self.assertEqual(f.cleaned_data['nick_name'], u'')
 
188
        self.assertEqual(f.cleaned_data['first_name'], u'John')
 
189
        self.assertEqual(f.cleaned_data['last_name'], u'Lennon')
 
190
 
 
191
        # For DateFields, it's set to None.
 
192
        class OptionalPersonForm(Form):
 
193
            first_name = CharField()
 
194
            last_name = CharField()
 
195
            birth_date = DateField(required=False)
 
196
 
 
197
        data = {'first_name': u'John', 'last_name': u'Lennon'}
 
198
        f = OptionalPersonForm(data)
 
199
        self.assertTrue(f.is_valid())
 
200
        self.assertEqual(f.cleaned_data['birth_date'], None)
 
201
        self.assertEqual(f.cleaned_data['first_name'], u'John')
 
202
        self.assertEqual(f.cleaned_data['last_name'], u'Lennon')
 
203
 
 
204
    def test_auto_id(self):
 
205
        # "auto_id" tells the Form to add an "id" attribute to each form element.
 
206
        # If it's a string that contains '%s', Django will use that as a format string
 
207
        # into which the field's name will be inserted. It will also put a <label> around
 
208
        # the human-readable labels for a field.
 
209
        p = Person(auto_id='%s_id')
 
210
        self.assertEqual(p.as_table(), """<tr><th><label for="first_name_id">First name:</label></th><td><input type="text" name="first_name" id="first_name_id" /></td></tr>
 
211
<tr><th><label for="last_name_id">Last name:</label></th><td><input type="text" name="last_name" id="last_name_id" /></td></tr>
 
212
<tr><th><label for="birthday_id">Birthday:</label></th><td><input type="text" name="birthday" id="birthday_id" /></td></tr>""")
 
213
        self.assertEqual(p.as_ul(), """<li><label for="first_name_id">First name:</label> <input type="text" name="first_name" id="first_name_id" /></li>
 
214
<li><label for="last_name_id">Last name:</label> <input type="text" name="last_name" id="last_name_id" /></li>
 
215
<li><label for="birthday_id">Birthday:</label> <input type="text" name="birthday" id="birthday_id" /></li>""")
 
216
        self.assertEqual(p.as_p(), """<p><label for="first_name_id">First name:</label> <input type="text" name="first_name" id="first_name_id" /></p>
 
217
<p><label for="last_name_id">Last name:</label> <input type="text" name="last_name" id="last_name_id" /></p>
 
218
<p><label for="birthday_id">Birthday:</label> <input type="text" name="birthday" id="birthday_id" /></p>""")
 
219
 
 
220
    def test_auto_id_true(self):
 
221
        # If auto_id is any True value whose str() does not contain '%s', the "id"
 
222
        # attribute will be the name of the field.
 
223
        p = Person(auto_id=True)
 
224
        self.assertEqual(p.as_ul(), """<li><label for="first_name">First name:</label> <input type="text" name="first_name" id="first_name" /></li>
 
225
<li><label for="last_name">Last name:</label> <input type="text" name="last_name" id="last_name" /></li>
 
226
<li><label for="birthday">Birthday:</label> <input type="text" name="birthday" id="birthday" /></li>""")
 
227
 
 
228
    def test_auto_id_false(self):
 
229
        # If auto_id is any False value, an "id" attribute won't be output unless it
 
230
        # was manually entered.
 
231
        p = Person(auto_id=False)
 
232
        self.assertEqual(p.as_ul(), """<li>First name: <input type="text" name="first_name" /></li>
 
233
<li>Last name: <input type="text" name="last_name" /></li>
 
234
<li>Birthday: <input type="text" name="birthday" /></li>""")
 
235
 
 
236
    def test_id_on_field(self):
 
237
        # In this example, auto_id is False, but the "id" attribute for the "first_name"
 
238
        # field is given. Also note that field gets a <label>, while the others don't.
 
239
        p = PersonNew(auto_id=False)
 
240
        self.assertEqual(p.as_ul(), """<li><label for="first_name_id">First name:</label> <input type="text" id="first_name_id" name="first_name" /></li>
 
241
<li>Last name: <input type="text" name="last_name" /></li>
 
242
<li>Birthday: <input type="text" name="birthday" /></li>""")
 
243
 
 
244
    def test_auto_id_on_form_and_field(self):
 
245
        # If the "id" attribute is specified in the Form and auto_id is True, the "id"
 
246
        # attribute in the Form gets precedence.
 
247
        p = PersonNew(auto_id=True)
 
248
        self.assertEqual(p.as_ul(), """<li><label for="first_name_id">First name:</label> <input type="text" id="first_name_id" name="first_name" /></li>
 
249
<li><label for="last_name">Last name:</label> <input type="text" name="last_name" id="last_name" /></li>
 
250
<li><label for="birthday">Birthday:</label> <input type="text" name="birthday" id="birthday" /></li>""")
 
251
 
 
252
    def test_various_boolean_values(self):
 
253
        class SignupForm(Form):
 
254
            email = EmailField()
 
255
            get_spam = BooleanField()
 
256
 
 
257
        f = SignupForm(auto_id=False)
 
258
        self.assertEqual(str(f['email']), '<input type="text" name="email" />')
 
259
        self.assertEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" />')
 
260
 
 
261
        f = SignupForm({'email': 'test@example.com', 'get_spam': True}, auto_id=False)
 
262
        self.assertEqual(str(f['email']), '<input type="text" name="email" value="test@example.com" />')
 
263
        self.assertEqual(str(f['get_spam']), '<input checked="checked" type="checkbox" name="get_spam" />')
 
264
 
 
265
        # 'True' or 'true' should be rendered without a value attribute
 
266
        f = SignupForm({'email': 'test@example.com', 'get_spam': 'True'}, auto_id=False)
 
267
        self.assertEqual(str(f['get_spam']), '<input checked="checked" type="checkbox" name="get_spam" />')
 
268
 
 
269
        f = SignupForm({'email': 'test@example.com', 'get_spam': 'true'}, auto_id=False)
 
270
        self.assertEqual(str(f['get_spam']), '<input checked="checked" type="checkbox" name="get_spam" />')
 
271
 
 
272
        # A value of 'False' or 'false' should be rendered unchecked
 
273
        f = SignupForm({'email': 'test@example.com', 'get_spam': 'False'}, auto_id=False)
 
274
        self.assertEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" />')
 
275
 
 
276
        f = SignupForm({'email': 'test@example.com', 'get_spam': 'false'}, auto_id=False)
 
277
        self.assertEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" />')
 
278
 
 
279
    def test_widget_output(self):
 
280
        # Any Field can have a Widget class passed to its constructor:
 
281
        class ContactForm(Form):
 
282
            subject = CharField()
 
283
            message = CharField(widget=Textarea)
 
284
 
 
285
        f = ContactForm(auto_id=False)
 
286
        self.assertEqual(str(f['subject']), '<input type="text" name="subject" />')
 
287
        self.assertEqual(str(f['message']), '<textarea rows="10" cols="40" name="message"></textarea>')
 
288
 
 
289
        # as_textarea(), as_text() and as_hidden() are shortcuts for changing the output
 
290
        # widget type:
 
291
        self.assertEqual(f['subject'].as_textarea(), u'<textarea rows="10" cols="40" name="subject"></textarea>')
 
292
        self.assertEqual(f['message'].as_text(), u'<input type="text" name="message" />')
 
293
        self.assertEqual(f['message'].as_hidden(), u'<input type="hidden" name="message" />')
 
294
 
 
295
        # The 'widget' parameter to a Field can also be an instance:
 
296
        class ContactForm(Form):
 
297
            subject = CharField()
 
298
            message = CharField(widget=Textarea(attrs={'rows': 80, 'cols': 20}))
 
299
 
 
300
        f = ContactForm(auto_id=False)
 
301
        self.assertEqual(str(f['message']), '<textarea rows="80" cols="20" name="message"></textarea>')
 
302
 
 
303
        # Instance-level attrs are *not* carried over to as_textarea(), as_text() and
 
304
        # as_hidden():
 
305
        self.assertEqual(f['message'].as_text(), u'<input type="text" name="message" />')
 
306
        f = ContactForm({'subject': 'Hello', 'message': 'I love you.'}, auto_id=False)
 
307
        self.assertEqual(f['subject'].as_textarea(), u'<textarea rows="10" cols="40" name="subject">Hello</textarea>')
 
308
        self.assertEqual(f['message'].as_text(), u'<input type="text" name="message" value="I love you." />')
 
309
        self.assertEqual(f['message'].as_hidden(), u'<input type="hidden" name="message" value="I love you." />')
 
310
 
 
311
    def test_forms_with_choices(self):
 
312
        # For a form with a <select>, use ChoiceField:
 
313
        class FrameworkForm(Form):
 
314
            name = CharField()
 
315
            language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')])
 
316
 
 
317
        f = FrameworkForm(auto_id=False)
 
318
        self.assertEqual(str(f['language']), """<select name="language">
 
319
<option value="P">Python</option>
 
320
<option value="J">Java</option>
 
321
</select>""")
 
322
        f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
 
323
        self.assertEqual(str(f['language']), """<select name="language">
 
324
<option value="P" selected="selected">Python</option>
 
325
<option value="J">Java</option>
 
326
</select>""")
 
327
 
 
328
        # A subtlety: If one of the choices' value is the empty string and the form is
 
329
        # unbound, then the <option> for the empty-string choice will get selected="selected".
 
330
        class FrameworkForm(Form):
 
331
            name = CharField()
 
332
            language = ChoiceField(choices=[('', '------'), ('P', 'Python'), ('J', 'Java')])
 
333
 
 
334
        f = FrameworkForm(auto_id=False)
 
335
        self.assertEqual(str(f['language']), """<select name="language">
 
336
<option value="" selected="selected">------</option>
 
337
<option value="P">Python</option>
 
338
<option value="J">Java</option>
 
339
</select>""")
 
340
 
 
341
        # You can specify widget attributes in the Widget constructor.
 
342
        class FrameworkForm(Form):
 
343
            name = CharField()
 
344
            language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=Select(attrs={'class': 'foo'}))
 
345
 
 
346
        f = FrameworkForm(auto_id=False)
 
347
        self.assertEqual(str(f['language']), """<select class="foo" name="language">
 
348
<option value="P">Python</option>
 
349
<option value="J">Java</option>
 
350
</select>""")
 
351
        f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
 
352
        self.assertEqual(str(f['language']), """<select class="foo" name="language">
 
353
<option value="P" selected="selected">Python</option>
 
354
<option value="J">Java</option>
 
355
</select>""")
 
356
 
 
357
        # When passing a custom widget instance to ChoiceField, note that setting
 
358
        # 'choices' on the widget is meaningless. The widget will use the choices
 
359
        # defined on the Field, not the ones defined on the Widget.
 
360
        class FrameworkForm(Form):
 
361
            name = CharField()
 
362
            language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=Select(choices=[('R', 'Ruby'), ('P', 'Perl')], attrs={'class': 'foo'}))
 
363
 
 
364
        f = FrameworkForm(auto_id=False)
 
365
        self.assertEqual(str(f['language']), """<select class="foo" name="language">
 
366
<option value="P">Python</option>
 
367
<option value="J">Java</option>
 
368
</select>""")
 
369
        f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
 
370
        self.assertEqual(str(f['language']), """<select class="foo" name="language">
 
371
<option value="P" selected="selected">Python</option>
 
372
<option value="J">Java</option>
 
373
</select>""")
 
374
 
 
375
        # You can set a ChoiceField's choices after the fact.
 
376
        class FrameworkForm(Form):
 
377
            name = CharField()
 
378
            language = ChoiceField()
 
379
 
 
380
        f = FrameworkForm(auto_id=False)
 
381
        self.assertEqual(str(f['language']), """<select name="language">
 
382
</select>""")
 
383
        f.fields['language'].choices = [('P', 'Python'), ('J', 'Java')]
 
384
        self.assertEqual(str(f['language']), """<select name="language">
 
385
<option value="P">Python</option>
 
386
<option value="J">Java</option>
 
387
</select>""")
 
388
 
 
389
    def test_forms_with_radio(self):
 
390
        # Add widget=RadioSelect to use that widget with a ChoiceField.
 
391
        class FrameworkForm(Form):
 
392
            name = CharField()
 
393
            language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=RadioSelect)
 
394
 
 
395
        f = FrameworkForm(auto_id=False)
 
396
        self.assertEqual(str(f['language']), """<ul>
 
397
<li><label><input type="radio" name="language" value="P" /> Python</label></li>
 
398
<li><label><input type="radio" name="language" value="J" /> Java</label></li>
 
399
</ul>""")
 
400
        self.assertEqual(f.as_table(), """<tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
 
401
<tr><th>Language:</th><td><ul>
 
402
<li><label><input type="radio" name="language" value="P" /> Python</label></li>
 
403
<li><label><input type="radio" name="language" value="J" /> Java</label></li>
 
404
</ul></td></tr>""")
 
405
        self.assertEqual(f.as_ul(), """<li>Name: <input type="text" name="name" /></li>
 
406
<li>Language: <ul>
 
407
<li><label><input type="radio" name="language" value="P" /> Python</label></li>
 
408
<li><label><input type="radio" name="language" value="J" /> Java</label></li>
 
409
</ul></li>""")
 
410
 
 
411
        # Regarding auto_id and <label>, RadioSelect is a special case. Each radio button
 
412
        # gets a distinct ID, formed by appending an underscore plus the button's
 
413
        # zero-based index.
 
414
        f = FrameworkForm(auto_id='id_%s')
 
415
        self.assertEqual(str(f['language']), """<ul>
 
416
<li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li>
 
417
<li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li>
 
418
</ul>""")
 
419
 
 
420
        # When RadioSelect is used with auto_id, and the whole form is printed using
 
421
        # either as_table() or as_ul(), the label for the RadioSelect will point to the
 
422
        # ID of the *first* radio button.
 
423
        self.assertEqual(f.as_table(), """<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" id="id_name" /></td></tr>
 
424
<tr><th><label for="id_language_0">Language:</label></th><td><ul>
 
425
<li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li>
 
426
<li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li>
 
427
</ul></td></tr>""")
 
428
        self.assertEqual(f.as_ul(), """<li><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></li>
 
429
<li><label for="id_language_0">Language:</label> <ul>
 
430
<li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li>
 
431
<li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li>
 
432
</ul></li>""")
 
433
        self.assertEqual(f.as_p(), """<p><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></p>
 
434
<p><label for="id_language_0">Language:</label> <ul>
 
435
<li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li>
 
436
<li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li>
 
437
</ul></p>""")
 
438
 
 
439
    def test_forms_wit_hmultiple_choice(self):
 
440
        # MultipleChoiceField is a special case, as its data is required to be a list:
 
441
        class SongForm(Form):
 
442
            name = CharField()
 
443
            composers = MultipleChoiceField()
 
444
 
 
445
        f = SongForm(auto_id=False)
 
446
        self.assertEqual(str(f['composers']), """<select multiple="multiple" name="composers">
 
447
</select>""")
 
448
 
 
449
        class SongForm(Form):
 
450
            name = CharField()
 
451
            composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')])
 
452
 
 
453
        f = SongForm(auto_id=False)
 
454
        self.assertEqual(str(f['composers']), """<select multiple="multiple" name="composers">
 
455
<option value="J">John Lennon</option>
 
456
<option value="P">Paul McCartney</option>
 
457
</select>""")
 
458
        f = SongForm({'name': 'Yesterday', 'composers': ['P']}, auto_id=False)
 
459
        self.assertEqual(str(f['name']), '<input type="text" name="name" value="Yesterday" />')
 
460
        self.assertEqual(str(f['composers']), """<select multiple="multiple" name="composers">
 
461
<option value="J">John Lennon</option>
 
462
<option value="P" selected="selected">Paul McCartney</option>
 
463
</select>""")
 
464
 
 
465
    def test_hidden_data(self):
 
466
        class SongForm(Form):
 
467
            name = CharField()
 
468
            composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')])
 
469
 
 
470
        # MultipleChoiceField rendered as_hidden() is a special case. Because it can
 
471
        # have multiple values, its as_hidden() renders multiple <input type="hidden">
 
472
        # tags.
 
473
        f = SongForm({'name': 'Yesterday', 'composers': ['P']}, auto_id=False)
 
474
        self.assertEqual(f['composers'].as_hidden(), '<input type="hidden" name="composers" value="P" />')
 
475
        f = SongForm({'name': 'From Me To You', 'composers': ['P', 'J']}, auto_id=False)
 
476
        self.assertEqual(f['composers'].as_hidden(), """<input type="hidden" name="composers" value="P" />
 
477
<input type="hidden" name="composers" value="J" />""")
 
478
 
 
479
    def test_mulitple_choice_checkbox(self):
 
480
        # MultipleChoiceField can also be used with the CheckboxSelectMultiple widget.
 
481
        class SongForm(Form):
 
482
            name = CharField()
 
483
            composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], widget=CheckboxSelectMultiple)
 
484
 
 
485
        f = SongForm(auto_id=False)
 
486
        self.assertEqual(str(f['composers']), """<ul>
 
487
<li><label><input type="checkbox" name="composers" value="J" /> John Lennon</label></li>
 
488
<li><label><input type="checkbox" name="composers" value="P" /> Paul McCartney</label></li>
 
489
</ul>""")
 
490
        f = SongForm({'composers': ['J']}, auto_id=False)
 
491
        self.assertEqual(str(f['composers']), """<ul>
 
492
<li><label><input checked="checked" type="checkbox" name="composers" value="J" /> John Lennon</label></li>
 
493
<li><label><input type="checkbox" name="composers" value="P" /> Paul McCartney</label></li>
 
494
</ul>""")
 
495
        f = SongForm({'composers': ['J', 'P']}, auto_id=False)
 
496
        self.assertEqual(str(f['composers']), """<ul>
 
497
<li><label><input checked="checked" type="checkbox" name="composers" value="J" /> John Lennon</label></li>
 
498
<li><label><input checked="checked" type="checkbox" name="composers" value="P" /> Paul McCartney</label></li>
 
499
</ul>""")
 
500
 
 
501
    def test_checkbox_auto_id(self):
 
502
        # Regarding auto_id, CheckboxSelectMultiple is a special case. Each checkbox
 
503
        # gets a distinct ID, formed by appending an underscore plus the checkbox's
 
504
        # zero-based index.
 
505
        class SongForm(Form):
 
506
            name = CharField()
 
507
            composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], widget=CheckboxSelectMultiple)
 
508
 
 
509
        f = SongForm(auto_id='%s_id')
 
510
        self.assertEqual(str(f['composers']), """<ul>
 
511
<li><label for="composers_id_0"><input type="checkbox" name="composers" value="J" id="composers_id_0" /> John Lennon</label></li>
 
512
<li><label for="composers_id_1"><input type="checkbox" name="composers" value="P" id="composers_id_1" /> Paul McCartney</label></li>
 
513
</ul>""")
 
514
 
 
515
    def test_multiple_choice_list_data(self):
 
516
        # Data for a MultipleChoiceField should be a list. QueryDict, MultiValueDict and
 
517
        # MergeDict (when created as a merge of MultiValueDicts) conveniently work with
 
518
        # this.
 
519
        class SongForm(Form):
 
520
            name = CharField()
 
521
            composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], widget=CheckboxSelectMultiple)
 
522
 
 
523
        data = {'name': 'Yesterday', 'composers': ['J', 'P']}
 
524
        f = SongForm(data)
 
525
        self.assertEqual(f.errors, {})
 
526
 
 
527
        data = QueryDict('name=Yesterday&composers=J&composers=P')
 
528
        f = SongForm(data)
 
529
        self.assertEqual(f.errors, {})
 
530
 
 
531
        data = MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P']))
 
532
        f = SongForm(data)
 
533
        self.assertEqual(f.errors, {})
 
534
 
 
535
        data = MergeDict(MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P'])))
 
536
        f = SongForm(data)
 
537
        self.assertEqual(f.errors, {})
 
538
 
 
539
    def test_multiple_hidden(self):
 
540
        class SongForm(Form):
 
541
            name = CharField()
 
542
            composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], widget=CheckboxSelectMultiple)
 
543
 
 
544
        # The MultipleHiddenInput widget renders multiple values as hidden fields.
 
545
        class SongFormHidden(Form):
 
546
            name = CharField()
 
547
            composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], widget=MultipleHiddenInput)
 
548
 
 
549
        f = SongFormHidden(MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P'])), auto_id=False)
 
550
        self.assertEqual(f.as_ul(), """<li>Name: <input type="text" name="name" value="Yesterday" /><input type="hidden" name="composers" value="J" />
 
551
<input type="hidden" name="composers" value="P" /></li>""")
 
552
 
 
553
        # When using CheckboxSelectMultiple, the framework expects a list of input and
 
554
        # returns a list of input.
 
555
        f = SongForm({'name': 'Yesterday'}, auto_id=False)
 
556
        self.assertEqual(f.errors['composers'], [u'This field is required.'])
 
557
        f = SongForm({'name': 'Yesterday', 'composers': ['J']}, auto_id=False)
 
558
        self.assertEqual(f.errors, {})
 
559
        self.assertEqual(f.cleaned_data['composers'], [u'J'])
 
560
        self.assertEqual(f.cleaned_data['name'], u'Yesterday')
 
561
        f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}, auto_id=False)
 
562
        self.assertEqual(f.errors, {})
 
563
        self.assertEqual(f.cleaned_data['composers'], [u'J', u'P'])
 
564
        self.assertEqual(f.cleaned_data['name'], u'Yesterday')
 
565
 
 
566
    def test_escaping(self):
 
567
        # Validation errors are HTML-escaped when output as HTML.
 
568
        class EscapingForm(Form):
 
569
            special_name = CharField(label="<em>Special</em> Field")
 
570
            special_safe_name = CharField(label=mark_safe("<em>Special</em> Field"))
 
571
 
 
572
            def clean_special_name(self):
 
573
                raise ValidationError("Something's wrong with '%s'" % self.cleaned_data['special_name'])
 
574
 
 
575
            def clean_special_safe_name(self):
 
576
                raise ValidationError(mark_safe("'<b>%s</b>' is a safe string" % self.cleaned_data['special_safe_name']))
 
577
 
 
578
        f = EscapingForm({'special_name': "Nothing to escape", 'special_safe_name': "Nothing to escape"}, auto_id=False)
 
579
        self.assertEqual(f.as_table(), """<tr><th>&lt;em&gt;Special&lt;/em&gt; Field:</th><td><ul class="errorlist"><li>Something&#39;s wrong with &#39;Nothing to escape&#39;</li></ul><input type="text" name="special_name" value="Nothing to escape" /></td></tr>
 
580
<tr><th><em>Special</em> Field:</th><td><ul class="errorlist"><li>'<b>Nothing to escape</b>' is a safe string</li></ul><input type="text" name="special_safe_name" value="Nothing to escape" /></td></tr>""")
 
581
        f = EscapingForm({
 
582
            'special_name': "Should escape < & > and <script>alert('xss')</script>",
 
583
            'special_safe_name': "<i>Do not escape</i>"
 
584
        }, auto_id=False)
 
585
        self.assertEqual(f.as_table(), """<tr><th>&lt;em&gt;Special&lt;/em&gt; Field:</th><td><ul class="errorlist"><li>Something&#39;s wrong with &#39;Should escape &lt; &amp; &gt; and &lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;&#39;</li></ul><input type="text" name="special_name" value="Should escape &lt; &amp; &gt; and &lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;" /></td></tr>
 
586
<tr><th><em>Special</em> Field:</th><td><ul class="errorlist"><li>'<b><i>Do not escape</i></b>' is a safe string</li></ul><input type="text" name="special_safe_name" value="&lt;i&gt;Do not escape&lt;/i&gt;" /></td></tr>""")
 
587
 
 
588
    def test_validating_multiple_fields(self):
 
589
        # There are a couple of ways to do multiple-field validation. If you want the
 
590
        # validation message to be associated with a particular field, implement the
 
591
        # clean_XXX() method on the Form, where XXX is the field name. As in
 
592
        # Field.clean(), the clean_XXX() method should return the cleaned value. In the
 
593
        # clean_XXX() method, you have access to self.cleaned_data, which is a dictionary
 
594
        # of all the data that has been cleaned *so far*, in order by the fields,
 
595
        # including the current field (e.g., the field XXX if you're in clean_XXX()).
 
596
        class UserRegistration(Form):
 
597
            username = CharField(max_length=10)
 
598
            password1 = CharField(widget=PasswordInput)
 
599
            password2 = CharField(widget=PasswordInput)
 
600
 
 
601
            def clean_password2(self):
 
602
                if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
 
603
                    raise ValidationError(u'Please make sure your passwords match.')
 
604
 
 
605
                return self.cleaned_data['password2']
 
606
 
 
607
        f = UserRegistration(auto_id=False)
 
608
        self.assertEqual(f.errors, {})
 
609
        f = UserRegistration({}, auto_id=False)
 
610
        self.assertEqual(f.errors['username'], [u'This field is required.'])
 
611
        self.assertEqual(f.errors['password1'], [u'This field is required.'])
 
612
        self.assertEqual(f.errors['password2'], [u'This field is required.'])
 
613
        f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
 
614
        self.assertEqual(f.errors['password2'], [u'Please make sure your passwords match.'])
 
615
        f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
 
616
        self.assertEqual(f.errors, {})
 
617
        self.assertEqual(f.cleaned_data['username'], u'adrian')
 
618
        self.assertEqual(f.cleaned_data['password1'], u'foo')
 
619
        self.assertEqual(f.cleaned_data['password2'], u'foo')
 
620
 
 
621
        # Another way of doing multiple-field validation is by implementing the
 
622
        # Form's clean() method. If you do this, any ValidationError raised by that
 
623
        # method will not be associated with a particular field; it will have a
 
624
        # special-case association with the field named '__all__'.
 
625
        # Note that in Form.clean(), you have access to self.cleaned_data, a dictionary of
 
626
        # all the fields/values that have *not* raised a ValidationError. Also note
 
627
        # Form.clean() is required to return a dictionary of all clean data.
 
628
        class UserRegistration(Form):
 
629
            username = CharField(max_length=10)
 
630
            password1 = CharField(widget=PasswordInput)
 
631
            password2 = CharField(widget=PasswordInput)
 
632
 
 
633
            def clean(self):
 
634
                if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
 
635
                    raise ValidationError(u'Please make sure your passwords match.')
 
636
 
 
637
                return self.cleaned_data
 
638
 
 
639
        f = UserRegistration(auto_id=False)
 
640
        self.assertEqual(f.errors, {})
 
641
        f = UserRegistration({}, auto_id=False)
 
642
        self.assertEqual(f.as_table(), """<tr><th>Username:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="username" maxlength="10" /></td></tr>
 
643
<tr><th>Password1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="password" name="password1" /></td></tr>
 
644
<tr><th>Password2:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="password" name="password2" /></td></tr>""")
 
645
        self.assertEqual(f.errors['username'], [u'This field is required.'])
 
646
        self.assertEqual(f.errors['password1'], [u'This field is required.'])
 
647
        self.assertEqual(f.errors['password2'], [u'This field is required.'])
 
648
        f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
 
649
        self.assertEqual(f.errors['__all__'], [u'Please make sure your passwords match.'])
 
650
        self.assertEqual(f.as_table(), """<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr>
 
651
<tr><th>Username:</th><td><input type="text" name="username" value="adrian" maxlength="10" /></td></tr>
 
652
<tr><th>Password1:</th><td><input type="password" name="password1" value="foo" /></td></tr>
 
653
<tr><th>Password2:</th><td><input type="password" name="password2" value="bar" /></td></tr>""")
 
654
        self.assertEqual(f.as_ul(), """<li><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></li>
 
655
<li>Username: <input type="text" name="username" value="adrian" maxlength="10" /></li>
 
656
<li>Password1: <input type="password" name="password1" value="foo" /></li>
 
657
<li>Password2: <input type="password" name="password2" value="bar" /></li>""")
 
658
        f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
 
659
        self.assertEqual(f.errors, {})
 
660
        self.assertEqual(f.cleaned_data['username'], u'adrian')
 
661
        self.assertEqual(f.cleaned_data['password1'], u'foo')
 
662
        self.assertEqual(f.cleaned_data['password2'], u'foo')
 
663
 
 
664
    def test_dynamic_construction(self):
 
665
        # It's possible to construct a Form dynamically by adding to the self.fields
 
666
        # dictionary in __init__(). Don't forget to call Form.__init__() within the
 
667
        # subclass' __init__().
 
668
        class Person(Form):
 
669
            first_name = CharField()
 
670
            last_name = CharField()
 
671
 
 
672
            def __init__(self, *args, **kwargs):
 
673
                super(Person, self).__init__(*args, **kwargs)
 
674
                self.fields['birthday'] = DateField()
 
675
 
 
676
        p = Person(auto_id=False)
 
677
        self.assertEqual(p.as_table(), """<tr><th>First name:</th><td><input type="text" name="first_name" /></td></tr>
 
678
<tr><th>Last name:</th><td><input type="text" name="last_name" /></td></tr>
 
679
<tr><th>Birthday:</th><td><input type="text" name="birthday" /></td></tr>""")
 
680
 
 
681
        # Instances of a dynamic Form do not persist fields from one Form instance to
 
682
        # the next.
 
683
        class MyForm(Form):
 
684
            def __init__(self, data=None, auto_id=False, field_list=[]):
 
685
                Form.__init__(self, data, auto_id=auto_id)
 
686
 
 
687
                for field in field_list:
 
688
                    self.fields[field[0]] = field[1]
 
689
 
 
690
        field_list = [('field1', CharField()), ('field2', CharField())]
 
691
        my_form = MyForm(field_list=field_list)
 
692
        self.assertEqual(my_form.as_table(), """<tr><th>Field1:</th><td><input type="text" name="field1" /></td></tr>
 
693
<tr><th>Field2:</th><td><input type="text" name="field2" /></td></tr>""")
 
694
        field_list = [('field3', CharField()), ('field4', CharField())]
 
695
        my_form = MyForm(field_list=field_list)
 
696
        self.assertEqual(my_form.as_table(), """<tr><th>Field3:</th><td><input type="text" name="field3" /></td></tr>
 
697
<tr><th>Field4:</th><td><input type="text" name="field4" /></td></tr>""")
 
698
 
 
699
        class MyForm(Form):
 
700
            default_field_1 = CharField()
 
701
            default_field_2 = CharField()
 
702
 
 
703
            def __init__(self, data=None, auto_id=False, field_list=[]):
 
704
                Form.__init__(self, data, auto_id=auto_id)
 
705
 
 
706
                for field in field_list:
 
707
                    self.fields[field[0]] = field[1]
 
708
 
 
709
        field_list = [('field1', CharField()), ('field2', CharField())]
 
710
        my_form = MyForm(field_list=field_list)
 
711
        self.assertEqual(my_form.as_table(), """<tr><th>Default field 1:</th><td><input type="text" name="default_field_1" /></td></tr>
 
712
<tr><th>Default field 2:</th><td><input type="text" name="default_field_2" /></td></tr>
 
713
<tr><th>Field1:</th><td><input type="text" name="field1" /></td></tr>
 
714
<tr><th>Field2:</th><td><input type="text" name="field2" /></td></tr>""")
 
715
        field_list = [('field3', CharField()), ('field4', CharField())]
 
716
        my_form = MyForm(field_list=field_list)
 
717
        self.assertEqual(my_form.as_table(), """<tr><th>Default field 1:</th><td><input type="text" name="default_field_1" /></td></tr>
 
718
<tr><th>Default field 2:</th><td><input type="text" name="default_field_2" /></td></tr>
 
719
<tr><th>Field3:</th><td><input type="text" name="field3" /></td></tr>
 
720
<tr><th>Field4:</th><td><input type="text" name="field4" /></td></tr>""")
 
721
 
 
722
        # Similarly, changes to field attributes do not persist from one Form instance
 
723
        # to the next.
 
724
        class Person(Form):
 
725
            first_name = CharField(required=False)
 
726
            last_name = CharField(required=False)
 
727
 
 
728
            def __init__(self, names_required=False, *args, **kwargs):
 
729
                super(Person, self).__init__(*args, **kwargs)
 
730
 
 
731
                if names_required:
 
732
                    self.fields['first_name'].required = True
 
733
                    self.fields['first_name'].widget.attrs['class'] = 'required'
 
734
                    self.fields['last_name'].required = True
 
735
                    self.fields['last_name'].widget.attrs['class'] = 'required'
 
736
 
 
737
        f = Person(names_required=False)
 
738
        self.assertEqual(f['first_name'].field.required, f['last_name'].field.required, (False, False))
 
739
        self.assertEqual(f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs, ({}, {}))
 
740
        f = Person(names_required=True)
 
741
        self.assertEqual(f['first_name'].field.required, f['last_name'].field.required, (True, True))
 
742
        self.assertEqual(f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs, ({'class': 'required'}, {'class': 'required'}))
 
743
        f = Person(names_required=False)
 
744
        self.assertEqual(f['first_name'].field.required, f['last_name'].field.required, (False, False))
 
745
        self.assertEqual(f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs, ({}, {}))
 
746
 
 
747
        class Person(Form):
 
748
            first_name = CharField(max_length=30)
 
749
            last_name = CharField(max_length=30)
 
750
 
 
751
            def __init__(self, name_max_length=None, *args, **kwargs):
 
752
                super(Person, self).__init__(*args, **kwargs)
 
753
 
 
754
                if name_max_length:
 
755
                    self.fields['first_name'].max_length = name_max_length
 
756
                    self.fields['last_name'].max_length = name_max_length
 
757
 
 
758
        f = Person(name_max_length=None)
 
759
        self.assertEqual(f['first_name'].field.max_length, f['last_name'].field.max_length, (30, 30))
 
760
        f = Person(name_max_length=20)
 
761
        self.assertEqual(f['first_name'].field.max_length, f['last_name'].field.max_length, (20, 20))
 
762
        f = Person(name_max_length=None)
 
763
        self.assertEqual(f['first_name'].field.max_length, f['last_name'].field.max_length, (30, 30))
 
764
 
 
765
    def test_hidden_widget(self):
 
766
        # HiddenInput widgets are displayed differently in the as_table(), as_ul())
 
767
        # and as_p() output of a Form -- their verbose names are not displayed, and a
 
768
        # separate row is not displayed. They're displayed in the last row of the
 
769
        # form, directly after that row's form element.
 
770
        class Person(Form):
 
771
            first_name = CharField()
 
772
            last_name = CharField()
 
773
            hidden_text = CharField(widget=HiddenInput)
 
774
            birthday = DateField()
 
775
 
 
776
        p = Person(auto_id=False)
 
777
        self.assertEqual(p.as_table(), """<tr><th>First name:</th><td><input type="text" name="first_name" /></td></tr>
 
778
<tr><th>Last name:</th><td><input type="text" name="last_name" /></td></tr>
 
779
<tr><th>Birthday:</th><td><input type="text" name="birthday" /><input type="hidden" name="hidden_text" /></td></tr>""")
 
780
        self.assertEqual(p.as_ul(), """<li>First name: <input type="text" name="first_name" /></li>
 
781
<li>Last name: <input type="text" name="last_name" /></li>
 
782
<li>Birthday: <input type="text" name="birthday" /><input type="hidden" name="hidden_text" /></li>""")
 
783
        self.assertEqual(p.as_p(), """<p>First name: <input type="text" name="first_name" /></p>
 
784
<p>Last name: <input type="text" name="last_name" /></p>
 
785
<p>Birthday: <input type="text" name="birthday" /><input type="hidden" name="hidden_text" /></p>""")
 
786
 
 
787
        # With auto_id set, a HiddenInput still gets an ID, but it doesn't get a label.
 
788
        p = Person(auto_id='id_%s')
 
789
        self.assertEqual(p.as_table(), """<tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" id="id_first_name" /></td></tr>
 
790
<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" id="id_last_name" /></td></tr>
 
791
<tr><th><label for="id_birthday">Birthday:</label></th><td><input type="text" name="birthday" id="id_birthday" /><input type="hidden" name="hidden_text" id="id_hidden_text" /></td></tr>""")
 
792
        self.assertEqual(p.as_ul(), """<li><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></li>
 
793
<li><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></li>
 
794
<li><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /><input type="hidden" name="hidden_text" id="id_hidden_text" /></li>""")
 
795
        self.assertEqual(p.as_p(), """<p><label for="id_first_name">First name:</label> <input type="text" name="first_name" id="id_first_name" /></p>
 
796
<p><label for="id_last_name">Last name:</label> <input type="text" name="last_name" id="id_last_name" /></p>
 
797
<p><label for="id_birthday">Birthday:</label> <input type="text" name="birthday" id="id_birthday" /><input type="hidden" name="hidden_text" id="id_hidden_text" /></p>""")
 
798
 
 
799
        # If a field with a HiddenInput has errors, the as_table() and as_ul() output
 
800
        # will include the error message(s) with the text "(Hidden field [fieldname]) "
 
801
        # prepended. This message is displayed at the top of the output, regardless of
 
802
        # its field's order in the form.
 
803
        p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': '1940-10-9'}, auto_id=False)
 
804
        self.assertEqual(p.as_table(), """<tr><td colspan="2"><ul class="errorlist"><li>(Hidden field hidden_text) This field is required.</li></ul></td></tr>
 
805
<tr><th>First name:</th><td><input type="text" name="first_name" value="John" /></td></tr>
 
806
<tr><th>Last name:</th><td><input type="text" name="last_name" value="Lennon" /></td></tr>
 
807
<tr><th>Birthday:</th><td><input type="text" name="birthday" value="1940-10-9" /><input type="hidden" name="hidden_text" /></td></tr>""")
 
808
        self.assertEqual(p.as_ul(), """<li><ul class="errorlist"><li>(Hidden field hidden_text) This field is required.</li></ul></li>
 
809
<li>First name: <input type="text" name="first_name" value="John" /></li>
 
810
<li>Last name: <input type="text" name="last_name" value="Lennon" /></li>
 
811
<li>Birthday: <input type="text" name="birthday" value="1940-10-9" /><input type="hidden" name="hidden_text" /></li>""")
 
812
        self.assertEqual(p.as_p(), """<ul class="errorlist"><li>(Hidden field hidden_text) This field is required.</li></ul>
 
813
<p>First name: <input type="text" name="first_name" value="John" /></p>
 
814
<p>Last name: <input type="text" name="last_name" value="Lennon" /></p>
 
815
<p>Birthday: <input type="text" name="birthday" value="1940-10-9" /><input type="hidden" name="hidden_text" /></p>""")
 
816
 
 
817
        # A corner case: It's possible for a form to have only HiddenInputs.
 
818
        class TestForm(Form):
 
819
            foo = CharField(widget=HiddenInput)
 
820
            bar = CharField(widget=HiddenInput)
 
821
 
 
822
        p = TestForm(auto_id=False)
 
823
        self.assertEqual(p.as_table(), '<input type="hidden" name="foo" /><input type="hidden" name="bar" />')
 
824
        self.assertEqual(p.as_ul(), '<input type="hidden" name="foo" /><input type="hidden" name="bar" />')
 
825
        self.assertEqual(p.as_p(), '<input type="hidden" name="foo" /><input type="hidden" name="bar" />')
 
826
 
 
827
    def test_field_order(self):
 
828
        # A Form's fields are displayed in the same order in which they were defined.
 
829
        class TestForm(Form):
 
830
            field1 = CharField()
 
831
            field2 = CharField()
 
832
            field3 = CharField()
 
833
            field4 = CharField()
 
834
            field5 = CharField()
 
835
            field6 = CharField()
 
836
            field7 = CharField()
 
837
            field8 = CharField()
 
838
            field9 = CharField()
 
839
            field10 = CharField()
 
840
            field11 = CharField()
 
841
            field12 = CharField()
 
842
            field13 = CharField()
 
843
            field14 = CharField()
 
844
 
 
845
        p = TestForm(auto_id=False)
 
846
        self.assertEqual(p.as_table(), """<tr><th>Field1:</th><td><input type="text" name="field1" /></td></tr>
 
847
<tr><th>Field2:</th><td><input type="text" name="field2" /></td></tr>
 
848
<tr><th>Field3:</th><td><input type="text" name="field3" /></td></tr>
 
849
<tr><th>Field4:</th><td><input type="text" name="field4" /></td></tr>
 
850
<tr><th>Field5:</th><td><input type="text" name="field5" /></td></tr>
 
851
<tr><th>Field6:</th><td><input type="text" name="field6" /></td></tr>
 
852
<tr><th>Field7:</th><td><input type="text" name="field7" /></td></tr>
 
853
<tr><th>Field8:</th><td><input type="text" name="field8" /></td></tr>
 
854
<tr><th>Field9:</th><td><input type="text" name="field9" /></td></tr>
 
855
<tr><th>Field10:</th><td><input type="text" name="field10" /></td></tr>
 
856
<tr><th>Field11:</th><td><input type="text" name="field11" /></td></tr>
 
857
<tr><th>Field12:</th><td><input type="text" name="field12" /></td></tr>
 
858
<tr><th>Field13:</th><td><input type="text" name="field13" /></td></tr>
 
859
<tr><th>Field14:</th><td><input type="text" name="field14" /></td></tr>""")
 
860
 
 
861
    def test_form_html_attributes(self):
 
862
        # Some Field classes have an effect on the HTML attributes of their associated
 
863
        # Widget. If you set max_length in a CharField and its associated widget is
 
864
        # either a TextInput or PasswordInput, then the widget's rendered HTML will
 
865
        # include the "maxlength" attribute.
 
866
        class UserRegistration(Form):
 
867
            username = CharField(max_length=10)                   # uses TextInput by default
 
868
            password = CharField(max_length=10, widget=PasswordInput)
 
869
            realname = CharField(max_length=10, widget=TextInput) # redundantly define widget, just to test
 
870
            address = CharField()                                 # no max_length defined here
 
871
 
 
872
        p = UserRegistration(auto_id=False)
 
873
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" maxlength="10" /></li>
 
874
<li>Password: <input type="password" name="password" maxlength="10" /></li>
 
875
<li>Realname: <input type="text" name="realname" maxlength="10" /></li>
 
876
<li>Address: <input type="text" name="address" /></li>""")
 
877
 
 
878
        # If you specify a custom "attrs" that includes the "maxlength" attribute,
 
879
        # the Field's max_length attribute will override whatever "maxlength" you specify
 
880
        # in "attrs".
 
881
        class UserRegistration(Form):
 
882
            username = CharField(max_length=10, widget=TextInput(attrs={'maxlength': 20}))
 
883
            password = CharField(max_length=10, widget=PasswordInput)
 
884
 
 
885
        p = UserRegistration(auto_id=False)
 
886
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" maxlength="10" /></li>
 
887
<li>Password: <input type="password" name="password" maxlength="10" /></li>""")
 
888
 
 
889
    def test_specifying_labels(self):
 
890
        # You can specify the label for a field by using the 'label' argument to a Field
 
891
        # class. If you don't specify 'label', Django will use the field name with
 
892
        # underscores converted to spaces, and the initial letter capitalized.
 
893
        class UserRegistration(Form):
 
894
            username = CharField(max_length=10, label='Your username')
 
895
            password1 = CharField(widget=PasswordInput)
 
896
            password2 = CharField(widget=PasswordInput, label='Password (again)')
 
897
 
 
898
        p = UserRegistration(auto_id=False)
 
899
        self.assertEqual(p.as_ul(), """<li>Your username: <input type="text" name="username" maxlength="10" /></li>
 
900
<li>Password1: <input type="password" name="password1" /></li>
 
901
<li>Password (again): <input type="password" name="password2" /></li>""")
 
902
 
 
903
        # Labels for as_* methods will only end in a colon if they don't end in other
 
904
        # punctuation already.
 
905
        class Questions(Form):
 
906
            q1 = CharField(label='The first question')
 
907
            q2 = CharField(label='What is your name?')
 
908
            q3 = CharField(label='The answer to life is:')
 
909
            q4 = CharField(label='Answer this question!')
 
910
            q5 = CharField(label='The last question. Period.')
 
911
 
 
912
        self.assertEqual(Questions(auto_id=False).as_p(), """<p>The first question: <input type="text" name="q1" /></p>
 
913
<p>What is your name? <input type="text" name="q2" /></p>
 
914
<p>The answer to life is: <input type="text" name="q3" /></p>
 
915
<p>Answer this question! <input type="text" name="q4" /></p>
 
916
<p>The last question. Period. <input type="text" name="q5" /></p>""")
 
917
        self.assertEqual(Questions().as_p(), """<p><label for="id_q1">The first question:</label> <input type="text" name="q1" id="id_q1" /></p>
 
918
<p><label for="id_q2">What is your name?</label> <input type="text" name="q2" id="id_q2" /></p>
 
919
<p><label for="id_q3">The answer to life is:</label> <input type="text" name="q3" id="id_q3" /></p>
 
920
<p><label for="id_q4">Answer this question!</label> <input type="text" name="q4" id="id_q4" /></p>
 
921
<p><label for="id_q5">The last question. Period.</label> <input type="text" name="q5" id="id_q5" /></p>""")
 
922
 
 
923
        # A label can be a Unicode object or a bytestring with special characters.
 
924
        class UserRegistration(Form):
 
925
            username = CharField(max_length=10, label='ŠĐĆŽćžšđ')
 
926
            password = CharField(widget=PasswordInput, label=u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111')
 
927
 
 
928
        p = UserRegistration(auto_id=False)
 
929
        self.assertEqual(p.as_ul(), u'<li>\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111: <input type="text" name="username" maxlength="10" /></li>\n<li>\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111: <input type="password" name="password" /></li>')
 
930
 
 
931
        # If a label is set to the empty string for a field, that field won't get a label.
 
932
        class UserRegistration(Form):
 
933
            username = CharField(max_length=10, label='')
 
934
            password = CharField(widget=PasswordInput)
 
935
 
 
936
        p = UserRegistration(auto_id=False)
 
937
        self.assertEqual(p.as_ul(), """<li> <input type="text" name="username" maxlength="10" /></li>
 
938
<li>Password: <input type="password" name="password" /></li>""")
 
939
        p = UserRegistration(auto_id='id_%s')
 
940
        self.assertEqual(p.as_ul(), """<li> <input id="id_username" type="text" name="username" maxlength="10" /></li>
 
941
<li><label for="id_password">Password:</label> <input type="password" name="password" id="id_password" /></li>""")
 
942
 
 
943
        # If label is None, Django will auto-create the label from the field name. This
 
944
        # is default behavior.
 
945
        class UserRegistration(Form):
 
946
            username = CharField(max_length=10, label=None)
 
947
            password = CharField(widget=PasswordInput)
 
948
 
 
949
        p = UserRegistration(auto_id=False)
 
950
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" maxlength="10" /></li>
 
951
<li>Password: <input type="password" name="password" /></li>""")
 
952
        p = UserRegistration(auto_id='id_%s')
 
953
        self.assertEqual(p.as_ul(), """<li><label for="id_username">Username:</label> <input id="id_username" type="text" name="username" maxlength="10" /></li>
 
954
<li><label for="id_password">Password:</label> <input type="password" name="password" id="id_password" /></li>""")
 
955
 
 
956
    def test_label_suffix(self):
 
957
        # You can specify the 'label_suffix' argument to a Form class to modify the
 
958
        # punctuation symbol used at the end of a label.  By default, the colon (:) is
 
959
        # used, and is only appended to the label if the label doesn't already end with a
 
960
        # punctuation symbol: ., !, ? or :.  If you specify a different suffix, it will
 
961
        # be appended regardless of the last character of the label.
 
962
        class FavoriteForm(Form):
 
963
            color = CharField(label='Favorite color?')
 
964
            animal = CharField(label='Favorite animal')
 
965
 
 
966
        f = FavoriteForm(auto_id=False)
 
967
        self.assertEqual(f.as_ul(), """<li>Favorite color? <input type="text" name="color" /></li>
 
968
<li>Favorite animal: <input type="text" name="animal" /></li>""")
 
969
        f = FavoriteForm(auto_id=False, label_suffix='?')
 
970
        self.assertEqual(f.as_ul(), """<li>Favorite color? <input type="text" name="color" /></li>
 
971
<li>Favorite animal? <input type="text" name="animal" /></li>""")
 
972
        f = FavoriteForm(auto_id=False, label_suffix='')
 
973
        self.assertEqual(f.as_ul(), """<li>Favorite color? <input type="text" name="color" /></li>
 
974
<li>Favorite animal <input type="text" name="animal" /></li>""")
 
975
        f = FavoriteForm(auto_id=False, label_suffix=u'\u2192')
 
976
        self.assertEqual(f.as_ul(), u'<li>Favorite color? <input type="text" name="color" /></li>\n<li>Favorite animal\u2192 <input type="text" name="animal" /></li>')
 
977
 
 
978
    def test_initial_data(self):
 
979
        # You can specify initial data for a field by using the 'initial' argument to a
 
980
        # Field class. This initial data is displayed when a Form is rendered with *no*
 
981
        # data. It is not displayed when a Form is rendered with any data (including an
 
982
        # empty dictionary). Also, the initial value is *not* used if data for a
 
983
        # particular required field isn't provided.
 
984
        class UserRegistration(Form):
 
985
            username = CharField(max_length=10, initial='django')
 
986
            password = CharField(widget=PasswordInput)
 
987
 
 
988
        # Here, we're not submitting any data, so the initial value will be displayed.)
 
989
        p = UserRegistration(auto_id=False)
 
990
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li>
 
991
<li>Password: <input type="password" name="password" /></li>""")
 
992
 
 
993
        # Here, we're submitting data, so the initial value will *not* be displayed.
 
994
        p = UserRegistration({}, auto_id=False)
 
995
        self.assertEqual(p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
 
996
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>""")
 
997
        p = UserRegistration({'username': u''}, auto_id=False)
 
998
        self.assertEqual(p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
 
999
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>""")
 
1000
        p = UserRegistration({'username': u'foo'}, auto_id=False)
 
1001
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="foo" maxlength="10" /></li>
 
1002
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>""")
 
1003
 
 
1004
        # An 'initial' value is *not* used as a fallback if data is not provided. In this
 
1005
        # example, we don't provide a value for 'username', and the form raises a
 
1006
        # validation error rather than using the initial value for 'username'.
 
1007
        p = UserRegistration({'password': 'secret'})
 
1008
        self.assertEqual(p.errors['username'], [u'This field is required.'])
 
1009
        self.assertFalse(p.is_valid())
 
1010
 
 
1011
    def test_dynamic_initial_data(self):
 
1012
        # The previous technique dealt with "hard-coded" initial data, but it's also
 
1013
        # possible to specify initial data after you've already created the Form class
 
1014
        # (i.e., at runtime). Use the 'initial' parameter to the Form constructor. This
 
1015
        # should be a dictionary containing initial values for one or more fields in the
 
1016
        # form, keyed by field name.
 
1017
        class UserRegistration(Form):
 
1018
            username = CharField(max_length=10)
 
1019
            password = CharField(widget=PasswordInput)
 
1020
 
 
1021
        # Here, we're not submitting any data, so the initial value will be displayed.)
 
1022
        p = UserRegistration(initial={'username': 'django'}, auto_id=False)
 
1023
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li>
 
1024
<li>Password: <input type="password" name="password" /></li>""")
 
1025
        p = UserRegistration(initial={'username': 'stephane'}, auto_id=False)
 
1026
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="stephane" maxlength="10" /></li>
 
1027
<li>Password: <input type="password" name="password" /></li>""")
 
1028
 
 
1029
        # The 'initial' parameter is meaningless if you pass data.
 
1030
        p = UserRegistration({}, initial={'username': 'django'}, auto_id=False)
 
1031
        self.assertEqual(p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
 
1032
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>""")
 
1033
        p = UserRegistration({'username': u''}, initial={'username': 'django'}, auto_id=False)
 
1034
        self.assertEqual(p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
 
1035
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>""")
 
1036
        p = UserRegistration({'username': u'foo'}, initial={'username': 'django'}, auto_id=False)
 
1037
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="foo" maxlength="10" /></li>
 
1038
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>""")
 
1039
 
 
1040
        # A dynamic 'initial' value is *not* used as a fallback if data is not provided.
 
1041
        # In this example, we don't provide a value for 'username', and the form raises a
 
1042
        # validation error rather than using the initial value for 'username'.
 
1043
        p = UserRegistration({'password': 'secret'}, initial={'username': 'django'})
 
1044
        self.assertEqual(p.errors['username'], [u'This field is required.'])
 
1045
        self.assertFalse(p.is_valid())
 
1046
 
 
1047
        # If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(),
 
1048
        # then the latter will get precedence.
 
1049
        class UserRegistration(Form):
 
1050
            username = CharField(max_length=10, initial='django')
 
1051
            password = CharField(widget=PasswordInput)
 
1052
 
 
1053
        p = UserRegistration(initial={'username': 'babik'}, auto_id=False)
 
1054
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="babik" maxlength="10" /></li>
 
1055
<li>Password: <input type="password" name="password" /></li>""")
 
1056
 
 
1057
    def test_callable_initial_data(self):
 
1058
        # The previous technique dealt with raw values as initial data, but it's also
 
1059
        # possible to specify callable data.
 
1060
        class UserRegistration(Form):
 
1061
            username = CharField(max_length=10)
 
1062
            password = CharField(widget=PasswordInput)
 
1063
            options = MultipleChoiceField(choices=[('f','foo'),('b','bar'),('w','whiz')])
 
1064
 
 
1065
        # We need to define functions that get called later.)
 
1066
        def initial_django():
 
1067
            return 'django'
 
1068
 
 
1069
        def initial_stephane():
 
1070
            return 'stephane'
 
1071
 
 
1072
        def initial_options():
 
1073
            return ['f','b']
 
1074
 
 
1075
        def initial_other_options():
 
1076
            return ['b','w']
 
1077
 
 
1078
        # Here, we're not submitting any data, so the initial value will be displayed.)
 
1079
        p = UserRegistration(initial={'username': initial_django, 'options': initial_options}, auto_id=False)
 
1080
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li>
 
1081
<li>Password: <input type="password" name="password" /></li>
 
1082
<li>Options: <select multiple="multiple" name="options">
 
1083
<option value="f" selected="selected">foo</option>
 
1084
<option value="b" selected="selected">bar</option>
 
1085
<option value="w">whiz</option>
 
1086
</select></li>""")
 
1087
 
 
1088
        # The 'initial' parameter is meaningless if you pass data.
 
1089
        p = UserRegistration({}, initial={'username': initial_django, 'options': initial_options}, auto_id=False)
 
1090
        self.assertEqual(p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
 
1091
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
 
1092
<li><ul class="errorlist"><li>This field is required.</li></ul>Options: <select multiple="multiple" name="options">
 
1093
<option value="f">foo</option>
 
1094
<option value="b">bar</option>
 
1095
<option value="w">whiz</option>
 
1096
</select></li>""")
 
1097
        p = UserRegistration({'username': u''}, initial={'username': initial_django}, auto_id=False)
 
1098
        self.assertEqual(p.as_ul(), """<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li>
 
1099
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
 
1100
<li><ul class="errorlist"><li>This field is required.</li></ul>Options: <select multiple="multiple" name="options">
 
1101
<option value="f">foo</option>
 
1102
<option value="b">bar</option>
 
1103
<option value="w">whiz</option>
 
1104
</select></li>""")
 
1105
        p = UserRegistration({'username': u'foo', 'options':['f','b']}, initial={'username': initial_django}, auto_id=False)
 
1106
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="foo" maxlength="10" /></li>
 
1107
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /></li>
 
1108
<li>Options: <select multiple="multiple" name="options">
 
1109
<option value="f" selected="selected">foo</option>
 
1110
<option value="b" selected="selected">bar</option>
 
1111
<option value="w">whiz</option>
 
1112
</select></li>""")
 
1113
 
 
1114
        # A callable 'initial' value is *not* used as a fallback if data is not provided.
 
1115
        # In this example, we don't provide a value for 'username', and the form raises a
 
1116
        # validation error rather than using the initial value for 'username'.
 
1117
        p = UserRegistration({'password': 'secret'}, initial={'username': initial_django, 'options': initial_options})
 
1118
        self.assertEqual(p.errors['username'], [u'This field is required.'])
 
1119
        self.assertFalse(p.is_valid())
 
1120
 
 
1121
        # If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(),
 
1122
        # then the latter will get precedence.
 
1123
        class UserRegistration(Form):
 
1124
           username = CharField(max_length=10, initial=initial_django)
 
1125
           password = CharField(widget=PasswordInput)
 
1126
           options = MultipleChoiceField(choices=[('f','foo'),('b','bar'),('w','whiz')], initial=initial_other_options)
 
1127
 
 
1128
        p = UserRegistration(auto_id=False)
 
1129
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="django" maxlength="10" /></li>
 
1130
<li>Password: <input type="password" name="password" /></li>
 
1131
<li>Options: <select multiple="multiple" name="options">
 
1132
<option value="f">foo</option>
 
1133
<option value="b" selected="selected">bar</option>
 
1134
<option value="w" selected="selected">whiz</option>
 
1135
</select></li>""")
 
1136
        p = UserRegistration(initial={'username': initial_stephane, 'options': initial_options}, auto_id=False)
 
1137
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="stephane" maxlength="10" /></li>
 
1138
<li>Password: <input type="password" name="password" /></li>
 
1139
<li>Options: <select multiple="multiple" name="options">
 
1140
<option value="f" selected="selected">foo</option>
 
1141
<option value="b" selected="selected">bar</option>
 
1142
<option value="w">whiz</option>
 
1143
</select></li>""")
 
1144
 
 
1145
    def test_help_text(self):
 
1146
        # You can specify descriptive text for a field by using the 'help_text' argument)
 
1147
        class UserRegistration(Form):
 
1148
            username = CharField(max_length=10, help_text='e.g., user@example.com')
 
1149
            password = CharField(widget=PasswordInput, help_text='Choose wisely.')
 
1150
 
 
1151
        p = UserRegistration(auto_id=False)
 
1152
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" maxlength="10" /> e.g., user@example.com</li>
 
1153
<li>Password: <input type="password" name="password" /> Choose wisely.</li>""")
 
1154
        self.assertEqual(p.as_p(), """<p>Username: <input type="text" name="username" maxlength="10" /> e.g., user@example.com</p>
 
1155
<p>Password: <input type="password" name="password" /> Choose wisely.</p>""")
 
1156
        self.assertEqual(p.as_table(), """<tr><th>Username:</th><td><input type="text" name="username" maxlength="10" /><br />e.g., user@example.com</td></tr>
 
1157
<tr><th>Password:</th><td><input type="password" name="password" /><br />Choose wisely.</td></tr>""")
 
1158
 
 
1159
        # The help text is displayed whether or not data is provided for the form.
 
1160
        p = UserRegistration({'username': u'foo'}, auto_id=False)
 
1161
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" value="foo" maxlength="10" /> e.g., user@example.com</li>
 
1162
<li><ul class="errorlist"><li>This field is required.</li></ul>Password: <input type="password" name="password" /> Choose wisely.</li>""")
 
1163
 
 
1164
        # help_text is not displayed for hidden fields. It can be used for documentation
 
1165
        # purposes, though.
 
1166
        class UserRegistration(Form):
 
1167
            username = CharField(max_length=10, help_text='e.g., user@example.com')
 
1168
            password = CharField(widget=PasswordInput)
 
1169
            next = CharField(widget=HiddenInput, initial='/', help_text='Redirect destination')
 
1170
 
 
1171
        p = UserRegistration(auto_id=False)
 
1172
        self.assertEqual(p.as_ul(), """<li>Username: <input type="text" name="username" maxlength="10" /> e.g., user@example.com</li>
 
1173
<li>Password: <input type="password" name="password" /><input type="hidden" name="next" value="/" /></li>""")
 
1174
 
 
1175
        # Help text can include arbitrary Unicode characters.
 
1176
        class UserRegistration(Form):
 
1177
            username = CharField(max_length=10, help_text='ŠĐĆŽćžšđ')
 
1178
 
 
1179
        p = UserRegistration(auto_id=False)
 
1180
        self.assertEqual(p.as_ul(), u'<li>Username: <input type="text" name="username" maxlength="10" /> \u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111</li>')
 
1181
 
 
1182
    def test_subclassing_forms(self):
 
1183
        # You can subclass a Form to add fields. The resulting form subclass will have
 
1184
        # all of the fields of the parent Form, plus whichever fields you define in the
 
1185
        # subclass.
 
1186
        class Person(Form):
 
1187
            first_name = CharField()
 
1188
            last_name = CharField()
 
1189
            birthday = DateField()
 
1190
 
 
1191
        class Musician(Person):
 
1192
            instrument = CharField()
 
1193
 
 
1194
        p = Person(auto_id=False)
 
1195
        self.assertEqual(p.as_ul(), """<li>First name: <input type="text" name="first_name" /></li>
 
1196
<li>Last name: <input type="text" name="last_name" /></li>
 
1197
<li>Birthday: <input type="text" name="birthday" /></li>""")
 
1198
        m = Musician(auto_id=False)
 
1199
        self.assertEqual(m.as_ul(), """<li>First name: <input type="text" name="first_name" /></li>
 
1200
<li>Last name: <input type="text" name="last_name" /></li>
 
1201
<li>Birthday: <input type="text" name="birthday" /></li>
 
1202
<li>Instrument: <input type="text" name="instrument" /></li>""")
 
1203
 
 
1204
        # Yes, you can subclass multiple forms. The fields are added in the order in
 
1205
        # which the parent classes are listed.
 
1206
        class Person(Form):
 
1207
            first_name = CharField()
 
1208
            last_name = CharField()
 
1209
            birthday = DateField()
 
1210
 
 
1211
        class Instrument(Form):
 
1212
            instrument = CharField()
 
1213
 
 
1214
        class Beatle(Person, Instrument):
 
1215
            haircut_type = CharField()
 
1216
 
 
1217
        b = Beatle(auto_id=False)
 
1218
        self.assertEqual(b.as_ul(), """<li>First name: <input type="text" name="first_name" /></li>
 
1219
<li>Last name: <input type="text" name="last_name" /></li>
 
1220
<li>Birthday: <input type="text" name="birthday" /></li>
 
1221
<li>Instrument: <input type="text" name="instrument" /></li>
 
1222
<li>Haircut type: <input type="text" name="haircut_type" /></li>""")
 
1223
 
 
1224
    def test_forms_with_prefixes(self):
 
1225
        # Sometimes it's necessary to have multiple forms display on the same HTML page,
 
1226
        # or multiple copies of the same form. We can accomplish this with form prefixes.
 
1227
        # Pass the keyword argument 'prefix' to the Form constructor to use this feature.
 
1228
        # This value will be prepended to each HTML form field name. One way to think
 
1229
        # about this is "namespaces for HTML forms". Notice that in the data argument,
 
1230
        # each field's key has the prefix, in this case 'person1', prepended to the
 
1231
        # actual field name.
 
1232
        class Person(Form):
 
1233
            first_name = CharField()
 
1234
            last_name = CharField()
 
1235
            birthday = DateField()
 
1236
 
 
1237
        data = {
 
1238
            'person1-first_name': u'John',
 
1239
            'person1-last_name': u'Lennon',
 
1240
            'person1-birthday': u'1940-10-9'
 
1241
        }
 
1242
        p = Person(data, prefix='person1')
 
1243
        self.assertEqual(p.as_ul(), """<li><label for="id_person1-first_name">First name:</label> <input type="text" name="person1-first_name" value="John" id="id_person1-first_name" /></li>
 
1244
<li><label for="id_person1-last_name">Last name:</label> <input type="text" name="person1-last_name" value="Lennon" id="id_person1-last_name" /></li>
 
1245
<li><label for="id_person1-birthday">Birthday:</label> <input type="text" name="person1-birthday" value="1940-10-9" id="id_person1-birthday" /></li>""")
 
1246
        self.assertEqual(str(p['first_name']), '<input type="text" name="person1-first_name" value="John" id="id_person1-first_name" />')
 
1247
        self.assertEqual(str(p['last_name']), '<input type="text" name="person1-last_name" value="Lennon" id="id_person1-last_name" />')
 
1248
        self.assertEqual(str(p['birthday']), '<input type="text" name="person1-birthday" value="1940-10-9" id="id_person1-birthday" />')
 
1249
        self.assertEqual(p.errors, {})
 
1250
        self.assertTrue(p.is_valid())
 
1251
        self.assertEqual(p.cleaned_data['first_name'], u'John')
 
1252
        self.assertEqual(p.cleaned_data['last_name'], u'Lennon')
 
1253
        self.assertEqual(p.cleaned_data['birthday'], datetime.date(1940, 10, 9))
 
1254
 
 
1255
        # Let's try submitting some bad data to make sure form.errors and field.errors
 
1256
        # work as expected.
 
1257
        data = {
 
1258
            'person1-first_name': u'',
 
1259
            'person1-last_name': u'',
 
1260
            'person1-birthday': u''
 
1261
        }
 
1262
        p = Person(data, prefix='person1')
 
1263
        self.assertEqual(p.errors['first_name'], [u'This field is required.'])
 
1264
        self.assertEqual(p.errors['last_name'], [u'This field is required.'])
 
1265
        self.assertEqual(p.errors['birthday'], [u'This field is required.'])
 
1266
        self.assertEqual(p['first_name'].errors, [u'This field is required.'])
 
1267
        try:
 
1268
            p['person1-first_name'].errors
 
1269
            self.fail('Attempts to access non-existent fields should fail.')
 
1270
        except KeyError:
 
1271
            pass
 
1272
 
 
1273
        # In this example, the data doesn't have a prefix, but the form requires it, so
 
1274
        # the form doesn't "see" the fields.
 
1275
        data = {
 
1276
            'first_name': u'John',
 
1277
            'last_name': u'Lennon',
 
1278
            'birthday': u'1940-10-9'
 
1279
        }
 
1280
        p = Person(data, prefix='person1')
 
1281
        self.assertEqual(p.errors['first_name'], [u'This field is required.'])
 
1282
        self.assertEqual(p.errors['last_name'], [u'This field is required.'])
 
1283
        self.assertEqual(p.errors['birthday'], [u'This field is required.'])
 
1284
 
 
1285
        # With prefixes, a single data dictionary can hold data for multiple instances
 
1286
        # of the same form.
 
1287
        data = {
 
1288
            'person1-first_name': u'John',
 
1289
            'person1-last_name': u'Lennon',
 
1290
            'person1-birthday': u'1940-10-9',
 
1291
            'person2-first_name': u'Jim',
 
1292
            'person2-last_name': u'Morrison',
 
1293
            'person2-birthday': u'1943-12-8'
 
1294
        }
 
1295
        p1 = Person(data, prefix='person1')
 
1296
        self.assertTrue(p1.is_valid())
 
1297
        self.assertEqual(p1.cleaned_data['first_name'], u'John')
 
1298
        self.assertEqual(p1.cleaned_data['last_name'], u'Lennon')
 
1299
        self.assertEqual(p1.cleaned_data['birthday'], datetime.date(1940, 10, 9))
 
1300
        p2 = Person(data, prefix='person2')
 
1301
        self.assertTrue(p2.is_valid())
 
1302
        self.assertEqual(p2.cleaned_data['first_name'], u'Jim')
 
1303
        self.assertEqual(p2.cleaned_data['last_name'], u'Morrison')
 
1304
        self.assertEqual(p2.cleaned_data['birthday'], datetime.date(1943, 12, 8))
 
1305
 
 
1306
        # By default, forms append a hyphen between the prefix and the field name, but a
 
1307
        # form can alter that behavior by implementing the add_prefix() method. This
 
1308
        # method takes a field name and returns the prefixed field, according to
 
1309
        # self.prefix.
 
1310
        class Person(Form):
 
1311
            first_name = CharField()
 
1312
            last_name = CharField()
 
1313
            birthday = DateField()
 
1314
 
 
1315
            def add_prefix(self, field_name):
 
1316
                return self.prefix and '%s-prefix-%s' % (self.prefix, field_name) or field_name
 
1317
 
 
1318
        p = Person(prefix='foo')
 
1319
        self.assertEqual(p.as_ul(), """<li><label for="id_foo-prefix-first_name">First name:</label> <input type="text" name="foo-prefix-first_name" id="id_foo-prefix-first_name" /></li>
 
1320
<li><label for="id_foo-prefix-last_name">Last name:</label> <input type="text" name="foo-prefix-last_name" id="id_foo-prefix-last_name" /></li>
 
1321
<li><label for="id_foo-prefix-birthday">Birthday:</label> <input type="text" name="foo-prefix-birthday" id="id_foo-prefix-birthday" /></li>""")
 
1322
        data = {
 
1323
            'foo-prefix-first_name': u'John',
 
1324
            'foo-prefix-last_name': u'Lennon',
 
1325
            'foo-prefix-birthday': u'1940-10-9'
 
1326
        }
 
1327
        p = Person(data, prefix='foo')
 
1328
        self.assertTrue(p.is_valid())
 
1329
        self.assertEqual(p.cleaned_data['first_name'], u'John')
 
1330
        self.assertEqual(p.cleaned_data['last_name'], u'Lennon')
 
1331
        self.assertEqual(p.cleaned_data['birthday'], datetime.date(1940, 10, 9))
 
1332
 
 
1333
    def test_forms_with_null_boolean(self):
 
1334
        # NullBooleanField is a bit of a special case because its presentation (widget)
 
1335
        # is different than its data. This is handled transparently, though.
 
1336
        class Person(Form):
 
1337
            name = CharField()
 
1338
            is_cool = NullBooleanField()
 
1339
 
 
1340
        p = Person({'name': u'Joe'}, auto_id=False)
 
1341
        self.assertEqual(str(p['is_cool']), """<select name="is_cool">
 
1342
<option value="1" selected="selected">Unknown</option>
 
1343
<option value="2">Yes</option>
 
1344
<option value="3">No</option>
 
1345
</select>""")
 
1346
        p = Person({'name': u'Joe', 'is_cool': u'1'}, auto_id=False)
 
1347
        self.assertEqual(str(p['is_cool']), """<select name="is_cool">
 
1348
<option value="1" selected="selected">Unknown</option>
 
1349
<option value="2">Yes</option>
 
1350
<option value="3">No</option>
 
1351
</select>""")
 
1352
        p = Person({'name': u'Joe', 'is_cool': u'2'}, auto_id=False)
 
1353
        self.assertEqual(str(p['is_cool']), """<select name="is_cool">
 
1354
<option value="1">Unknown</option>
 
1355
<option value="2" selected="selected">Yes</option>
 
1356
<option value="3">No</option>
 
1357
</select>""")
 
1358
        p = Person({'name': u'Joe', 'is_cool': u'3'}, auto_id=False)
 
1359
        self.assertEqual(str(p['is_cool']), """<select name="is_cool">
 
1360
<option value="1">Unknown</option>
 
1361
<option value="2">Yes</option>
 
1362
<option value="3" selected="selected">No</option>
 
1363
</select>""")
 
1364
        p = Person({'name': u'Joe', 'is_cool': True}, auto_id=False)
 
1365
        self.assertEqual(str(p['is_cool']), """<select name="is_cool">
 
1366
<option value="1">Unknown</option>
 
1367
<option value="2" selected="selected">Yes</option>
 
1368
<option value="3">No</option>
 
1369
</select>""")
 
1370
        p = Person({'name': u'Joe', 'is_cool': False}, auto_id=False)
 
1371
        self.assertEqual(str(p['is_cool']), """<select name="is_cool">
 
1372
<option value="1">Unknown</option>
 
1373
<option value="2">Yes</option>
 
1374
<option value="3" selected="selected">No</option>
 
1375
</select>""")
 
1376
 
 
1377
    def test_forms_with_file_fields(self):
 
1378
        # FileFields are a special case because they take their data from the request.FILES,
 
1379
        # not request.POST.
 
1380
        class FileForm(Form):
 
1381
            file1 = FileField()
 
1382
 
 
1383
        f = FileForm(auto_id=False)
 
1384
        self.assertEqual(f.as_table(), '<tr><th>File1:</th><td><input type="file" name="file1" /></td></tr>')
 
1385
 
 
1386
        f = FileForm(data={}, files={}, auto_id=False)
 
1387
        self.assertEqual(f.as_table(), '<tr><th>File1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="file" name="file1" /></td></tr>')
 
1388
 
 
1389
        f = FileForm(data={}, files={'file1': SimpleUploadedFile('name', '')}, auto_id=False)
 
1390
        self.assertEqual(f.as_table(), '<tr><th>File1:</th><td><ul class="errorlist"><li>The submitted file is empty.</li></ul><input type="file" name="file1" /></td></tr>')
 
1391
 
 
1392
        f = FileForm(data={}, files={'file1': 'something that is not a file'}, auto_id=False)
 
1393
        self.assertEqual(f.as_table(), '<tr><th>File1:</th><td><ul class="errorlist"><li>No file was submitted. Check the encoding type on the form.</li></ul><input type="file" name="file1" /></td></tr>')
 
1394
 
 
1395
        f = FileForm(data={}, files={'file1': SimpleUploadedFile('name', 'some content')}, auto_id=False)
 
1396
        self.assertEqual(f.as_table(), '<tr><th>File1:</th><td><input type="file" name="file1" /></td></tr>')
 
1397
        self.assertTrue(f.is_valid())
 
1398
 
 
1399
        f = FileForm(data={}, files={'file1': SimpleUploadedFile('我隻氣墊船裝滿晒鱔.txt', 'मेरी मँडराने वाली नाव सर्पमीनों से भरी ह')}, auto_id=False)
 
1400
        self.assertEqual(f.as_table(), '<tr><th>File1:</th><td><input type="file" name="file1" /></td></tr>')
 
1401
 
 
1402
    def test_basic_processing_in_view(self):
 
1403
        class UserRegistration(Form):
 
1404
            username = CharField(max_length=10)
 
1405
            password1 = CharField(widget=PasswordInput)
 
1406
            password2 = CharField(widget=PasswordInput)
 
1407
 
 
1408
            def clean(self):
 
1409
                if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
 
1410
                    raise ValidationError(u'Please make sure your passwords match.')
 
1411
 
 
1412
                return self.cleaned_data
 
1413
 
 
1414
        def my_function(method, post_data):
 
1415
            if method == 'POST':
 
1416
                form = UserRegistration(post_data, auto_id=False)
 
1417
            else:
 
1418
                form = UserRegistration(auto_id=False)
 
1419
 
 
1420
            if form.is_valid():
 
1421
                return 'VALID: %r' % form.cleaned_data
 
1422
 
 
1423
            t = Template('<form action="" method="post">\n<table>\n{{ form }}\n</table>\n<input type="submit" />\n</form>')
 
1424
            return t.render(Context({'form': form}))
 
1425
 
 
1426
        # Case 1: GET (an empty form, with no errors).)
 
1427
        self.assertEqual(my_function('GET', {}), """<form action="" method="post">
 
1428
<table>
 
1429
<tr><th>Username:</th><td><input type="text" name="username" maxlength="10" /></td></tr>
 
1430
<tr><th>Password1:</th><td><input type="password" name="password1" /></td></tr>
 
1431
<tr><th>Password2:</th><td><input type="password" name="password2" /></td></tr>
 
1432
</table>
 
1433
<input type="submit" />
 
1434
</form>""")
 
1435
        # Case 2: POST with erroneous data (a redisplayed form, with errors).)
 
1436
        self.assertEqual(my_function('POST', {'username': 'this-is-a-long-username', 'password1': 'foo', 'password2': 'bar'}), """<form action="" method="post">
 
1437
<table>
 
1438
<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr>
 
1439
<tr><th>Username:</th><td><ul class="errorlist"><li>Ensure this value has at most 10 characters (it has 23).</li></ul><input type="text" name="username" value="this-is-a-long-username" maxlength="10" /></td></tr>
 
1440
<tr><th>Password1:</th><td><input type="password" name="password1" value="foo" /></td></tr>
 
1441
<tr><th>Password2:</th><td><input type="password" name="password2" value="bar" /></td></tr>
 
1442
</table>
 
1443
<input type="submit" />
 
1444
</form>""")
 
1445
        # Case 3: POST with valid data (the success message).)
 
1446
        self.assertEqual(my_function('POST', {'username': 'adrian', 'password1': 'secret', 'password2': 'secret'}), "VALID: {'username': u'adrian', 'password1': u'secret', 'password2': u'secret'}")
 
1447
 
 
1448
    def test_templates_with_forms(self):
 
1449
        class UserRegistration(Form):
 
1450
            username = CharField(max_length=10, help_text="Good luck picking a username that doesn't already exist.")
 
1451
            password1 = CharField(widget=PasswordInput)
 
1452
            password2 = CharField(widget=PasswordInput)
 
1453
 
 
1454
            def clean(self):
 
1455
                if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
 
1456
                    raise ValidationError(u'Please make sure your passwords match.')
 
1457
 
 
1458
                return self.cleaned_data
 
1459
 
 
1460
        # You have full flexibility in displaying form fields in a template. Just pass a
 
1461
        # Form instance to the template, and use "dot" access to refer to individual
 
1462
        # fields. Note, however, that this flexibility comes with the responsibility of
 
1463
        # displaying all the errors, including any that might not be associated with a
 
1464
        # particular field.
 
1465
        t = Template('''<form action="">
 
1466
{{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
 
1467
{{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
 
1468
{{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
 
1469
<input type="submit" />
 
1470
</form>''')
 
1471
        self.assertEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action="">
 
1472
<p><label>Your username: <input type="text" name="username" maxlength="10" /></label></p>
 
1473
<p><label>Password: <input type="password" name="password1" /></label></p>
 
1474
<p><label>Password (again): <input type="password" name="password2" /></label></p>
 
1475
<input type="submit" />
 
1476
</form>""")
 
1477
        self.assertEqual(t.render(Context({'form': UserRegistration({'username': 'django'}, auto_id=False)})), """<form action="">
 
1478
<p><label>Your username: <input type="text" name="username" value="django" maxlength="10" /></label></p>
 
1479
<ul class="errorlist"><li>This field is required.</li></ul><p><label>Password: <input type="password" name="password1" /></label></p>
 
1480
<ul class="errorlist"><li>This field is required.</li></ul><p><label>Password (again): <input type="password" name="password2" /></label></p>
 
1481
<input type="submit" />
 
1482
</form>""")
 
1483
 
 
1484
        # Use form.[field].label to output a field's label. You can specify the label for
 
1485
        # a field by using the 'label' argument to a Field class. If you don't specify
 
1486
        # 'label', Django will use the field name with underscores converted to spaces,
 
1487
        # and the initial letter capitalized.
 
1488
        t = Template('''<form action="">
 
1489
<p><label>{{ form.username.label }}: {{ form.username }}</label></p>
 
1490
<p><label>{{ form.password1.label }}: {{ form.password1 }}</label></p>
 
1491
<p><label>{{ form.password2.label }}: {{ form.password2 }}</label></p>
 
1492
<input type="submit" />
 
1493
</form>''')
 
1494
        self.assertEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action="">
 
1495
<p><label>Username: <input type="text" name="username" maxlength="10" /></label></p>
 
1496
<p><label>Password1: <input type="password" name="password1" /></label></p>
 
1497
<p><label>Password2: <input type="password" name="password2" /></label></p>
 
1498
<input type="submit" />
 
1499
</form>""")
 
1500
 
 
1501
        # User form.[field].label_tag to output a field's label with a <label> tag
 
1502
        # wrapped around it, but *only* if the given field has an "id" attribute.
 
1503
        # Recall from above that passing the "auto_id" argument to a Form gives each
 
1504
        # field an "id" attribute.
 
1505
        t = Template('''<form action="">
 
1506
<p>{{ form.username.label_tag }}: {{ form.username }}</p>
 
1507
<p>{{ form.password1.label_tag }}: {{ form.password1 }}</p>
 
1508
<p>{{ form.password2.label_tag }}: {{ form.password2 }}</p>
 
1509
<input type="submit" />
 
1510
</form>''')
 
1511
        self.assertEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action="">
 
1512
<p>Username: <input type="text" name="username" maxlength="10" /></p>
 
1513
<p>Password1: <input type="password" name="password1" /></p>
 
1514
<p>Password2: <input type="password" name="password2" /></p>
 
1515
<input type="submit" />
 
1516
</form>""")
 
1517
        self.assertEqual(t.render(Context({'form': UserRegistration(auto_id='id_%s')})), """<form action="">
 
1518
<p><label for="id_username">Username</label>: <input id="id_username" type="text" name="username" maxlength="10" /></p>
 
1519
<p><label for="id_password1">Password1</label>: <input type="password" name="password1" id="id_password1" /></p>
 
1520
<p><label for="id_password2">Password2</label>: <input type="password" name="password2" id="id_password2" /></p>
 
1521
<input type="submit" />
 
1522
</form>""")
 
1523
 
 
1524
        # User form.[field].help_text to output a field's help text. If the given field
 
1525
        # does not have help text, nothing will be output.
 
1526
        t = Template('''<form action="">
 
1527
<p>{{ form.username.label_tag }}: {{ form.username }}<br />{{ form.username.help_text }}</p>
 
1528
<p>{{ form.password1.label_tag }}: {{ form.password1 }}</p>
 
1529
<p>{{ form.password2.label_tag }}: {{ form.password2 }}</p>
 
1530
<input type="submit" />
 
1531
</form>''')
 
1532
        self.assertEqual(t.render(Context({'form': UserRegistration(auto_id=False)})), """<form action="">
 
1533
<p>Username: <input type="text" name="username" maxlength="10" /><br />Good luck picking a username that doesn&#39;t already exist.</p>
 
1534
<p>Password1: <input type="password" name="password1" /></p>
 
1535
<p>Password2: <input type="password" name="password2" /></p>
 
1536
<input type="submit" />
 
1537
</form>""")
 
1538
        self.assertEqual(Template('{{ form.password1.help_text }}').render(Context({'form': UserRegistration(auto_id=False)})), u'')
 
1539
 
 
1540
        # The label_tag() method takes an optional attrs argument: a dictionary of HTML
 
1541
        # attributes to add to the <label> tag.
 
1542
        f = UserRegistration(auto_id='id_%s')
 
1543
        form_output = []
 
1544
 
 
1545
        for bf in f:
 
1546
            form_output.append(bf.label_tag(attrs={'class': 'pretty'}))
 
1547
 
 
1548
        self.assertEqual(form_output, [
 
1549
            '<label for="id_username" class="pretty">Username</label>',
 
1550
            '<label for="id_password1" class="pretty">Password1</label>',
 
1551
            '<label for="id_password2" class="pretty">Password2</label>',
 
1552
        ])
 
1553
 
 
1554
        # To display the errors that aren't associated with a particular field -- e.g.,
 
1555
        # the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the
 
1556
        # template. If used on its own, it is displayed as a <ul> (or an empty string, if
 
1557
        # the list of errors is empty). You can also use it in {% if %} statements.
 
1558
        t = Template('''<form action="">
 
1559
{{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
 
1560
{{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
 
1561
{{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
 
1562
<input type="submit" />
 
1563
</form>''')
 
1564
        self.assertEqual(t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)})), """<form action="">
 
1565
<p><label>Your username: <input type="text" name="username" value="django" maxlength="10" /></label></p>
 
1566
<p><label>Password: <input type="password" name="password1" value="foo" /></label></p>
 
1567
<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p>
 
1568
<input type="submit" />
 
1569
</form>""")
 
1570
        t = Template('''<form action="">
 
1571
{{ form.non_field_errors }}
 
1572
{{ form.username.errors.as_ul }}<p><label>Your username: {{ form.username }}</label></p>
 
1573
{{ form.password1.errors.as_ul }}<p><label>Password: {{ form.password1 }}</label></p>
 
1574
{{ form.password2.errors.as_ul }}<p><label>Password (again): {{ form.password2 }}</label></p>
 
1575
<input type="submit" />
 
1576
</form>''')
 
1577
        self.assertEqual(t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)})), """<form action="">
 
1578
<ul class="errorlist"><li>Please make sure your passwords match.</li></ul>
 
1579
<p><label>Your username: <input type="text" name="username" value="django" maxlength="10" /></label></p>
 
1580
<p><label>Password: <input type="password" name="password1" value="foo" /></label></p>
 
1581
<p><label>Password (again): <input type="password" name="password2" value="bar" /></label></p>
 
1582
<input type="submit" />
 
1583
</form>""")
 
1584
 
 
1585
    def test_empty_permitted(self):
 
1586
        # Sometimes (pretty much in formsets) we want to allow a form to pass validation
 
1587
        # if it is completely empty. We can accomplish this by using the empty_permitted
 
1588
        # agrument to a form constructor.
 
1589
        class SongForm(Form):
 
1590
            artist = CharField()
 
1591
            name = CharField()
 
1592
 
 
1593
        # First let's show what happens id empty_permitted=False (the default):
 
1594
        data = {'artist': '', 'song': ''}
 
1595
        form = SongForm(data, empty_permitted=False)
 
1596
        self.assertFalse(form.is_valid())
 
1597
        self.assertEqual(form.errors, {'name': [u'This field is required.'], 'artist': [u'This field is required.']})
 
1598
        try:
 
1599
            form.cleaned_data
 
1600
            self.fail('Attempts to access cleaned_data when validation fails should fail.')
 
1601
        except AttributeError:
 
1602
            pass
 
1603
 
 
1604
        # Now let's show what happens when empty_permitted=True and the form is empty.
 
1605
        form = SongForm(data, empty_permitted=True)
 
1606
        self.assertTrue(form.is_valid())
 
1607
        self.assertEqual(form.errors, {})
 
1608
        self.assertEqual(form.cleaned_data, {})
 
1609
 
 
1610
        # But if we fill in data for one of the fields, the form is no longer empty and
 
1611
        # the whole thing must pass validation.
 
1612
        data = {'artist': 'The Doors', 'song': ''}
 
1613
        form = SongForm(data, empty_permitted=False)
 
1614
        self.assertFalse(form.is_valid())
 
1615
        self.assertEqual(form.errors, {'name': [u'This field is required.']})
 
1616
        try:
 
1617
            form.cleaned_data
 
1618
            self.fail('Attempts to access cleaned_data when validation fails should fail.')
 
1619
        except AttributeError:
 
1620
            pass
 
1621
 
 
1622
        # If a field is not given in the data then None is returned for its data. Lets
 
1623
        # make sure that when checking for empty_permitted that None is treated
 
1624
        # accordingly.
 
1625
        data = {'artist': None, 'song': ''}
 
1626
        form = SongForm(data, empty_permitted=True)
 
1627
        self.assertTrue(form.is_valid())
 
1628
 
 
1629
        # However, we *really* need to be sure we are checking for None as any data in
 
1630
        # initial that returns False on a boolean call needs to be treated literally.
 
1631
        class PriceForm(Form):
 
1632
            amount = FloatField()
 
1633
            qty = IntegerField()
 
1634
 
 
1635
        data = {'amount': '0.0', 'qty': ''}
 
1636
        form = PriceForm(data, initial={'amount': 0.0}, empty_permitted=True)
 
1637
        self.assertTrue(form.is_valid())
 
1638
 
 
1639
    def test_extracting_hidden_and_visible(self):
 
1640
        class SongForm(Form):
 
1641
            token = CharField(widget=HiddenInput)
 
1642
            artist = CharField()
 
1643
            name = CharField()
 
1644
 
 
1645
        form = SongForm()
 
1646
        self.assertEqual([f.name for f in form.hidden_fields()], ['token'])
 
1647
        self.assertEqual([f.name for f in form.visible_fields()], ['artist', 'name'])
 
1648
 
 
1649
    def test_hidden_initial_gets_id(self):
 
1650
        class MyForm(Form):
 
1651
            field1 = CharField(max_length=50, show_hidden_initial=True)
 
1652
 
 
1653
        self.assertEqual(MyForm().as_table(), '<tr><th><label for="id_field1">Field1:</label></th><td><input id="id_field1" type="text" name="field1" maxlength="50" /><input type="hidden" name="initial-field1" id="initial-id_field1" /></td></tr>')
 
1654
 
 
1655
    def test_error_html_required_html_classes(self):
 
1656
        class Person(Form):
 
1657
            name = CharField()
 
1658
            is_cool = NullBooleanField()
 
1659
            email = EmailField(required=False)
 
1660
            age = IntegerField()
 
1661
 
 
1662
        p = Person({})
 
1663
        p.error_css_class = 'error'
 
1664
        p.required_css_class = 'required'
 
1665
 
 
1666
        self.assertEqual(p.as_ul(), """<li class="required error"><ul class="errorlist"><li>This field is required.</li></ul><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></li>
 
1667
<li class="required"><label for="id_is_cool">Is cool:</label> <select name="is_cool" id="id_is_cool">
 
1668
<option value="1" selected="selected">Unknown</option>
 
1669
<option value="2">Yes</option>
 
1670
<option value="3">No</option>
 
1671
</select></li>
 
1672
<li><label for="id_email">Email:</label> <input type="text" name="email" id="id_email" /></li>
 
1673
<li class="required error"><ul class="errorlist"><li>This field is required.</li></ul><label for="id_age">Age:</label> <input type="text" name="age" id="id_age" /></li>""")
 
1674
 
 
1675
        self.assertEqual(p.as_p(), """<ul class="errorlist"><li>This field is required.</li></ul>
 
1676
<p class="required error"><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></p>
 
1677
<p class="required"><label for="id_is_cool">Is cool:</label> <select name="is_cool" id="id_is_cool">
 
1678
<option value="1" selected="selected">Unknown</option>
 
1679
<option value="2">Yes</option>
 
1680
<option value="3">No</option>
 
1681
</select></p>
 
1682
<p><label for="id_email">Email:</label> <input type="text" name="email" id="id_email" /></p>
 
1683
<ul class="errorlist"><li>This field is required.</li></ul>
 
1684
<p class="required error"><label for="id_age">Age:</label> <input type="text" name="age" id="id_age" /></p>""")
 
1685
 
 
1686
        self.assertEqual(p.as_table(), """<tr class="required error"><th><label for="id_name">Name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="name" id="id_name" /></td></tr>
 
1687
<tr class="required"><th><label for="id_is_cool">Is cool:</label></th><td><select name="is_cool" id="id_is_cool">
 
1688
<option value="1" selected="selected">Unknown</option>
 
1689
<option value="2">Yes</option>
 
1690
<option value="3">No</option>
 
1691
</select></td></tr>
 
1692
<tr><th><label for="id_email">Email:</label></th><td><input type="text" name="email" id="id_email" /></td></tr>
 
1693
<tr class="required error"><th><label for="id_age">Age:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="age" id="id_age" /></td></tr>""")
 
1694
 
 
1695
    def test_label_split_datetime_not_displayed(self):
 
1696
        class EventForm(Form):
 
1697
            happened_at = SplitDateTimeField(widget=widgets.SplitHiddenDateTimeWidget)
 
1698
 
 
1699
        form = EventForm()
 
1700
        self.assertEqual(form.as_ul(), u'<input type="hidden" name="happened_at_0" id="id_happened_at_0" /><input type="hidden" name="happened_at_1" id="id_happened_at_1" />')