~ubuntu-branches/debian/squeeze/python-django/squeeze

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb, Chris Lamb, David Spreen, Sandro Tosi
  • Date: 2008-11-19 21:31:00 UTC
  • mfrom: (1.2.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20081119213100-gp0lqhxl1qxa6dgl
Tags: 1.0.2-1
[ Chris Lamb ]
* New upstream bugfix release. Closes: #505783
* Add myself to Uploaders with ACK from Brett.

[ David Spreen ]
* Remove python-pysqlite2 from Recommends because Python 2.5 includes
  sqlite library used by Django. Closes: 497886

[ Sandro Tosi ]
* debian/control
  - switch Vcs-Browser field to viewsvn

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
tests = r"""
3
 
>>> from django.forms import *
4
 
>>> from django.forms.widgets import RadioFieldRenderer
5
 
>>> from django.utils.safestring import mark_safe
6
 
>>> import datetime
7
 
>>> import time
8
 
>>> import re
9
 
>>> try:
10
 
...     from decimal import Decimal
11
 
... except ImportError:
12
 
...     from django.utils._decimal import Decimal
13
 
 
14
 
###########
15
 
# Widgets #
16
 
###########
17
 
 
18
 
Each Widget class corresponds to an HTML form widget. A Widget knows how to
19
 
render itself, given a field name and some data. Widgets don't perform
20
 
validation.
21
 
 
22
 
# TextInput Widget ############################################################
23
 
 
24
 
>>> w = TextInput()
25
 
>>> w.render('email', '')
26
 
u'<input type="text" name="email" />'
27
 
>>> w.render('email', None)
28
 
u'<input type="text" name="email" />'
29
 
>>> w.render('email', 'test@example.com')
30
 
u'<input type="text" name="email" value="test@example.com" />'
31
 
>>> w.render('email', 'some "quoted" & ampersanded value')
32
 
u'<input type="text" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />'
33
 
>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
34
 
u'<input type="text" name="email" value="test@example.com" class="fun" />'
35
 
 
36
 
# Note that doctest in Python 2.4 (and maybe 2.5?) doesn't support non-ascii
37
 
# characters in output, so we're displaying the repr() here.
38
 
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
39
 
u'<input type="text" name="email" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" class="fun" />'
40
 
 
41
 
You can also pass 'attrs' to the constructor:
42
 
>>> w = TextInput(attrs={'class': 'fun'})
43
 
>>> w.render('email', '')
44
 
u'<input type="text" class="fun" name="email" />'
45
 
>>> w.render('email', 'foo@example.com')
46
 
u'<input type="text" class="fun" value="foo@example.com" name="email" />'
47
 
 
48
 
'attrs' passed to render() get precedence over those passed to the constructor:
49
 
>>> w = TextInput(attrs={'class': 'pretty'})
50
 
>>> w.render('email', '', attrs={'class': 'special'})
51
 
u'<input type="text" class="special" name="email" />'
52
 
 
53
 
'attrs' can be safe-strings if needed
54
 
>>> w = TextInput(attrs={'onBlur': mark_safe("function('foo')")})
55
 
>>> print w.render('email', '')
56
 
<input onBlur="function('foo')" type="text" name="email" />
57
 
 
58
 
# PasswordInput Widget ############################################################
59
 
 
60
 
>>> w = PasswordInput()
61
 
>>> w.render('email', '')
62
 
u'<input type="password" name="email" />'
63
 
>>> w.render('email', None)
64
 
u'<input type="password" name="email" />'
65
 
>>> w.render('email', 'test@example.com')
66
 
u'<input type="password" name="email" value="test@example.com" />'
67
 
>>> w.render('email', 'some "quoted" & ampersanded value')
68
 
u'<input type="password" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />'
69
 
>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
70
 
u'<input type="password" name="email" value="test@example.com" class="fun" />'
71
 
 
72
 
You can also pass 'attrs' to the constructor:
73
 
>>> w = PasswordInput(attrs={'class': 'fun'})
74
 
>>> w.render('email', '')
75
 
u'<input type="password" class="fun" name="email" />'
76
 
>>> w.render('email', 'foo@example.com')
77
 
u'<input type="password" class="fun" value="foo@example.com" name="email" />'
78
 
 
79
 
'attrs' passed to render() get precedence over those passed to the constructor:
80
 
>>> w = PasswordInput(attrs={'class': 'pretty'})
81
 
>>> w.render('email', '', attrs={'class': 'special'})
82
 
u'<input type="password" class="special" name="email" />'
83
 
 
84
 
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
85
 
u'<input type="password" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
86
 
 
87
 
The render_value argument lets you specify whether the widget should render
88
 
its value. You may want to do this for security reasons.
89
 
>>> w = PasswordInput(render_value=True)
90
 
>>> w.render('email', 'secret')
91
 
u'<input type="password" name="email" value="secret" />'
92
 
>>> w = PasswordInput(render_value=False)
93
 
>>> w.render('email', '')
94
 
u'<input type="password" name="email" />'
95
 
>>> w.render('email', None)
96
 
u'<input type="password" name="email" />'
97
 
>>> w.render('email', 'secret')
98
 
u'<input type="password" name="email" />'
99
 
>>> w = PasswordInput(attrs={'class': 'fun'}, render_value=False)
100
 
>>> w.render('email', 'secret')
101
 
u'<input type="password" class="fun" name="email" />'
102
 
 
103
 
# HiddenInput Widget ############################################################
104
 
 
105
 
>>> w = HiddenInput()
106
 
>>> w.render('email', '')
107
 
u'<input type="hidden" name="email" />'
108
 
>>> w.render('email', None)
109
 
u'<input type="hidden" name="email" />'
110
 
>>> w.render('email', 'test@example.com')
111
 
u'<input type="hidden" name="email" value="test@example.com" />'
112
 
>>> w.render('email', 'some "quoted" & ampersanded value')
113
 
u'<input type="hidden" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />'
114
 
>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
115
 
u'<input type="hidden" name="email" value="test@example.com" class="fun" />'
116
 
 
117
 
You can also pass 'attrs' to the constructor:
118
 
>>> w = HiddenInput(attrs={'class': 'fun'})
119
 
>>> w.render('email', '')
120
 
u'<input type="hidden" class="fun" name="email" />'
121
 
>>> w.render('email', 'foo@example.com')
122
 
u'<input type="hidden" class="fun" value="foo@example.com" name="email" />'
123
 
 
124
 
'attrs' passed to render() get precedence over those passed to the constructor:
125
 
>>> w = HiddenInput(attrs={'class': 'pretty'})
126
 
>>> w.render('email', '', attrs={'class': 'special'})
127
 
u'<input type="hidden" class="special" name="email" />'
128
 
 
129
 
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
130
 
u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
131
 
 
132
 
'attrs' passed to render() get precedence over those passed to the constructor:
133
 
>>> w = HiddenInput(attrs={'class': 'pretty'})
134
 
>>> w.render('email', '', attrs={'class': 'special'})
135
 
u'<input type="hidden" class="special" name="email" />'
136
 
 
137
 
Boolean values are rendered to their string forms ("True" and "False").
138
 
>>> w = HiddenInput()
139
 
>>> w.render('get_spam', False)
140
 
u'<input type="hidden" name="get_spam" value="False" />'
141
 
>>> w.render('get_spam', True)
142
 
u'<input type="hidden" name="get_spam" value="True" />'
143
 
 
144
 
# MultipleHiddenInput Widget ##################################################
145
 
 
146
 
>>> w = MultipleHiddenInput()
147
 
>>> w.render('email', [])
148
 
u''
149
 
>>> w.render('email', None)
150
 
u''
151
 
>>> w.render('email', ['test@example.com'])
152
 
u'<input type="hidden" name="email" value="test@example.com" />'
153
 
>>> w.render('email', ['some "quoted" & ampersanded value'])
154
 
u'<input type="hidden" name="email" value="some &quot;quoted&quot; &amp; ampersanded value" />'
155
 
>>> w.render('email', ['test@example.com', 'foo@example.com'])
156
 
u'<input type="hidden" name="email" value="test@example.com" />\n<input type="hidden" name="email" value="foo@example.com" />'
157
 
>>> w.render('email', ['test@example.com'], attrs={'class': 'fun'})
158
 
u'<input type="hidden" name="email" value="test@example.com" class="fun" />'
159
 
>>> w.render('email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'})
160
 
u'<input type="hidden" name="email" value="test@example.com" class="fun" />\n<input type="hidden" name="email" value="foo@example.com" class="fun" />'
161
 
 
162
 
You can also pass 'attrs' to the constructor:
163
 
>>> w = MultipleHiddenInput(attrs={'class': 'fun'})
164
 
>>> w.render('email', [])
165
 
u''
166
 
>>> w.render('email', ['foo@example.com'])
167
 
u'<input type="hidden" class="fun" value="foo@example.com" name="email" />'
168
 
>>> w.render('email', ['foo@example.com', 'test@example.com'])
169
 
u'<input type="hidden" class="fun" value="foo@example.com" name="email" />\n<input type="hidden" class="fun" value="test@example.com" name="email" />'
170
 
 
171
 
'attrs' passed to render() get precedence over those passed to the constructor:
172
 
>>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
173
 
>>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
174
 
u'<input type="hidden" class="special" value="foo@example.com" name="email" />'
175
 
 
176
 
>>> w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'})
177
 
u'<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />'
178
 
 
179
 
'attrs' passed to render() get precedence over those passed to the constructor:
180
 
>>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
181
 
>>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
182
 
u'<input type="hidden" class="special" value="foo@example.com" name="email" />'
183
 
 
184
 
# FileInput Widget ############################################################
185
 
 
186
 
FileInput widgets don't ever show the value, because the old value is of no use
187
 
if you are updating the form or if the provided file generated an error.
188
 
>>> w = FileInput()
189
 
>>> w.render('email', '')
190
 
u'<input type="file" name="email" />'
191
 
>>> w.render('email', None)
192
 
u'<input type="file" name="email" />'
193
 
>>> w.render('email', 'test@example.com')
194
 
u'<input type="file" name="email" />'
195
 
>>> w.render('email', 'some "quoted" & ampersanded value')
196
 
u'<input type="file" name="email" />'
197
 
>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
198
 
u'<input type="file" name="email" class="fun" />'
199
 
 
200
 
You can also pass 'attrs' to the constructor:
201
 
>>> w = FileInput(attrs={'class': 'fun'})
202
 
>>> w.render('email', '')
203
 
u'<input type="file" class="fun" name="email" />'
204
 
>>> w.render('email', 'foo@example.com')
205
 
u'<input type="file" class="fun" name="email" />'
206
 
 
207
 
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
208
 
u'<input type="file" class="fun" name="email" />'
209
 
 
210
 
Test for the behavior of _has_changed for FileInput. The value of data will
211
 
more than likely come from request.FILES. The value of initial data will
212
 
likely be a filename stored in the database. Since its value is of no use to
213
 
a FileInput it is ignored.
214
 
 
215
 
>>> w = FileInput()
216
 
 
217
 
# No file was uploaded and no initial data.
218
 
>>> w._has_changed(u'', None)
219
 
False
220
 
 
221
 
# A file was uploaded and no initial data.
222
 
>>> w._has_changed(u'', {'filename': 'resume.txt', 'content': 'My resume'})
223
 
True
224
 
 
225
 
# A file was not uploaded, but there is initial data
226
 
>>> w._has_changed(u'resume.txt', None)
227
 
False
228
 
 
229
 
# A file was uploaded and there is initial data (file identity is not dealt
230
 
# with here)
231
 
>>> w._has_changed('resume.txt', {'filename': 'resume.txt', 'content': 'My resume'})
232
 
True
233
 
 
234
 
# Textarea Widget #############################################################
235
 
 
236
 
>>> w = Textarea()
237
 
>>> w.render('msg', '')
238
 
u'<textarea rows="10" cols="40" name="msg"></textarea>'
239
 
>>> w.render('msg', None)
240
 
u'<textarea rows="10" cols="40" name="msg"></textarea>'
241
 
>>> w.render('msg', 'value')
242
 
u'<textarea rows="10" cols="40" name="msg">value</textarea>'
243
 
>>> w.render('msg', 'some "quoted" & ampersanded value')
244
 
u'<textarea rows="10" cols="40" name="msg">some &quot;quoted&quot; &amp; ampersanded value</textarea>'
245
 
>>> w.render('msg', mark_safe('pre &quot;quoted&quot; value'))
246
 
u'<textarea rows="10" cols="40" name="msg">pre &quot;quoted&quot; value</textarea>'
247
 
>>> w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20})
248
 
u'<textarea class="pretty" rows="20" cols="40" name="msg">value</textarea>'
249
 
 
250
 
You can also pass 'attrs' to the constructor:
251
 
>>> w = Textarea(attrs={'class': 'pretty'})
252
 
>>> w.render('msg', '')
253
 
u'<textarea rows="10" cols="40" name="msg" class="pretty"></textarea>'
254
 
>>> w.render('msg', 'example')
255
 
u'<textarea rows="10" cols="40" name="msg" class="pretty">example</textarea>'
256
 
 
257
 
'attrs' passed to render() get precedence over those passed to the constructor:
258
 
>>> w = Textarea(attrs={'class': 'pretty'})
259
 
>>> w.render('msg', '', attrs={'class': 'special'})
260
 
u'<textarea rows="10" cols="40" name="msg" class="special"></textarea>'
261
 
 
262
 
>>> w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
263
 
u'<textarea rows="10" cols="40" name="msg" class="fun">\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111</textarea>'
264
 
 
265
 
# CheckboxInput Widget ########################################################
266
 
 
267
 
>>> w = CheckboxInput()
268
 
>>> w.render('is_cool', '')
269
 
u'<input type="checkbox" name="is_cool" />'
270
 
>>> w.render('is_cool', None)
271
 
u'<input type="checkbox" name="is_cool" />'
272
 
>>> w.render('is_cool', False)
273
 
u'<input type="checkbox" name="is_cool" />'
274
 
>>> w.render('is_cool', True)
275
 
u'<input checked="checked" type="checkbox" name="is_cool" />'
276
 
 
277
 
Using any value that's not in ('', None, False, True) will check the checkbox
278
 
and set the 'value' attribute.
279
 
>>> w.render('is_cool', 'foo')
280
 
u'<input checked="checked" type="checkbox" name="is_cool" value="foo" />'
281
 
 
282
 
>>> w.render('is_cool', False, attrs={'class': 'pretty'})
283
 
u'<input type="checkbox" name="is_cool" class="pretty" />'
284
 
 
285
 
You can also pass 'attrs' to the constructor:
286
 
>>> w = CheckboxInput(attrs={'class': 'pretty'})
287
 
>>> w.render('is_cool', '')
288
 
u'<input type="checkbox" class="pretty" name="is_cool" />'
289
 
 
290
 
'attrs' passed to render() get precedence over those passed to the constructor:
291
 
>>> w = CheckboxInput(attrs={'class': 'pretty'})
292
 
>>> w.render('is_cool', '', attrs={'class': 'special'})
293
 
u'<input type="checkbox" class="special" name="is_cool" />'
294
 
 
295
 
You can pass 'check_test' to the constructor. This is a callable that takes the
296
 
value and returns True if the box should be checked.
297
 
>>> w = CheckboxInput(check_test=lambda value: value.startswith('hello'))
298
 
>>> w.render('greeting', '')
299
 
u'<input type="checkbox" name="greeting" />'
300
 
>>> w.render('greeting', 'hello')
301
 
u'<input checked="checked" type="checkbox" name="greeting" value="hello" />'
302
 
>>> w.render('greeting', 'hello there')
303
 
u'<input checked="checked" type="checkbox" name="greeting" value="hello there" />'
304
 
>>> w.render('greeting', 'hello & goodbye')
305
 
u'<input checked="checked" type="checkbox" name="greeting" value="hello &amp; goodbye" />'
306
 
 
307
 
A subtlety: If the 'check_test' argument cannot handle a value and raises any
308
 
exception during its __call__, then the exception will be swallowed and the box
309
 
will not be checked. In this example, the 'check_test' assumes the value has a
310
 
startswith() method, which fails for the values True, False and None.
311
 
>>> w.render('greeting', True)
312
 
u'<input type="checkbox" name="greeting" />'
313
 
>>> w.render('greeting', False)
314
 
u'<input type="checkbox" name="greeting" />'
315
 
>>> w.render('greeting', None)
316
 
u'<input type="checkbox" name="greeting" />'
317
 
 
318
 
The CheckboxInput widget will return False if the key is not found in the data
319
 
dictionary (because HTML form submission doesn't send any result for unchecked
320
 
checkboxes).
321
 
>>> w.value_from_datadict({}, {}, 'testing')
322
 
False
323
 
 
324
 
>>> w._has_changed(None, None)
325
 
False
326
 
>>> w._has_changed(None, u'')
327
 
False
328
 
>>> w._has_changed(u'', None)
329
 
False
330
 
>>> w._has_changed(u'', u'')
331
 
False
332
 
>>> w._has_changed(False, u'on')
333
 
True
334
 
>>> w._has_changed(True, u'on')
335
 
False
336
 
>>> w._has_changed(True, u'')
337
 
True
338
 
 
339
 
# Select Widget ###############################################################
340
 
 
341
 
>>> w = Select()
342
 
>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
343
 
<select name="beatle">
344
 
<option value="J" selected="selected">John</option>
345
 
<option value="P">Paul</option>
346
 
<option value="G">George</option>
347
 
<option value="R">Ringo</option>
348
 
</select>
349
 
 
350
 
If the value is None, none of the options are selected:
351
 
>>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
352
 
<select name="beatle">
353
 
<option value="J">John</option>
354
 
<option value="P">Paul</option>
355
 
<option value="G">George</option>
356
 
<option value="R">Ringo</option>
357
 
</select>
358
 
 
359
 
If the value corresponds to a label (but not to an option value), none of the options are selected:
360
 
>>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
361
 
<select name="beatle">
362
 
<option value="J">John</option>
363
 
<option value="P">Paul</option>
364
 
<option value="G">George</option>
365
 
<option value="R">Ringo</option>
366
 
</select>
367
 
 
368
 
The value is compared to its str():
369
 
>>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
370
 
<select name="num">
371
 
<option value="1">1</option>
372
 
<option value="2" selected="selected">2</option>
373
 
<option value="3">3</option>
374
 
</select>
375
 
>>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
376
 
<select name="num">
377
 
<option value="1">1</option>
378
 
<option value="2" selected="selected">2</option>
379
 
<option value="3">3</option>
380
 
</select>
381
 
>>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
382
 
<select name="num">
383
 
<option value="1">1</option>
384
 
<option value="2" selected="selected">2</option>
385
 
<option value="3">3</option>
386
 
</select>
387
 
 
388
 
The 'choices' argument can be any iterable:
389
 
>>> from itertools import chain
390
 
>>> def get_choices():
391
 
...     for i in range(5):
392
 
...         yield (i, i)
393
 
>>> print w.render('num', 2, choices=get_choices())
394
 
<select name="num">
395
 
<option value="0">0</option>
396
 
<option value="1">1</option>
397
 
<option value="2" selected="selected">2</option>
398
 
<option value="3">3</option>
399
 
<option value="4">4</option>
400
 
</select>
401
 
>>> things = ({'id': 1, 'name': 'And Boom'}, {'id': 2, 'name': 'One More Thing!'})
402
 
>>> class SomeForm(Form):
403
 
...     somechoice = ChoiceField(choices=chain((('', '-'*9),), [(thing['id'], thing['name']) for thing in things]))
404
 
>>> f = SomeForm()
405
 
>>> f.as_table()
406
 
u'<tr><th><label for="id_somechoice">Somechoice:</label></th><td><select name="somechoice" id="id_somechoice">\n<option value="" selected="selected">---------</option>\n<option value="1">And Boom</option>\n<option value="2">One More Thing!</option>\n</select></td></tr>'
407
 
>>> f.as_table()
408
 
u'<tr><th><label for="id_somechoice">Somechoice:</label></th><td><select name="somechoice" id="id_somechoice">\n<option value="" selected="selected">---------</option>\n<option value="1">And Boom</option>\n<option value="2">One More Thing!</option>\n</select></td></tr>'
409
 
>>> f = SomeForm({'somechoice': 2})
410
 
>>> f.as_table()
411
 
u'<tr><th><label for="id_somechoice">Somechoice:</label></th><td><select name="somechoice" id="id_somechoice">\n<option value="">---------</option>\n<option value="1">And Boom</option>\n<option value="2" selected="selected">One More Thing!</option>\n</select></td></tr>'
412
 
 
413
 
You can also pass 'choices' to the constructor:
414
 
>>> w = Select(choices=[(1, 1), (2, 2), (3, 3)])
415
 
>>> print w.render('num', 2)
416
 
<select name="num">
417
 
<option value="1">1</option>
418
 
<option value="2" selected="selected">2</option>
419
 
<option value="3">3</option>
420
 
</select>
421
 
 
422
 
If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
423
 
>>> print w.render('num', 2, choices=[(4, 4), (5, 5)])
424
 
<select name="num">
425
 
<option value="1">1</option>
426
 
<option value="2" selected="selected">2</option>
427
 
<option value="3">3</option>
428
 
<option value="4">4</option>
429
 
<option value="5">5</option>
430
 
</select>
431
 
 
432
 
# Choices are escaped correctly
433
 
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
434
 
<select name="escape">
435
 
<option value="1">1</option>
436
 
<option value="2">2</option>
437
 
<option value="3">3</option>
438
 
<option value="bad">you &amp; me</option>
439
 
<option value="good">you &gt; me</option>
440
 
</select>
441
 
 
442
 
# Unicode choices are correctly rendered as HTML
443
 
>>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
444
 
u'<select name="email">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
445
 
 
446
 
If choices is passed to the constructor and is a generator, it can be iterated
447
 
over multiple times without getting consumed:
448
 
>>> w = Select(choices=get_choices())
449
 
>>> print w.render('num', 2)
450
 
<select name="num">
451
 
<option value="0">0</option>
452
 
<option value="1">1</option>
453
 
<option value="2" selected="selected">2</option>
454
 
<option value="3">3</option>
455
 
<option value="4">4</option>
456
 
</select>
457
 
>>> print w.render('num', 3)
458
 
<select name="num">
459
 
<option value="0">0</option>
460
 
<option value="1">1</option>
461
 
<option value="2">2</option>
462
 
<option value="3" selected="selected">3</option>
463
 
<option value="4">4</option>
464
 
</select>
465
 
 
466
 
Choices can be nested one level in order to create HTML optgroups:
467
 
>>> w.choices=(('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2'))))
468
 
>>> print w.render('nestchoice', None)
469
 
<select name="nestchoice">
470
 
<option value="outer1">Outer 1</option>
471
 
<optgroup label="Group &quot;1&quot;">
472
 
<option value="inner1">Inner 1</option>
473
 
<option value="inner2">Inner 2</option>
474
 
</optgroup>
475
 
</select>
476
 
 
477
 
>>> print w.render('nestchoice', 'outer1')
478
 
<select name="nestchoice">
479
 
<option value="outer1" selected="selected">Outer 1</option>
480
 
<optgroup label="Group &quot;1&quot;">
481
 
<option value="inner1">Inner 1</option>
482
 
<option value="inner2">Inner 2</option>
483
 
</optgroup>
484
 
</select>
485
 
 
486
 
>>> print w.render('nestchoice', 'inner1')
487
 
<select name="nestchoice">
488
 
<option value="outer1">Outer 1</option>
489
 
<optgroup label="Group &quot;1&quot;">
490
 
<option value="inner1" selected="selected">Inner 1</option>
491
 
<option value="inner2">Inner 2</option>
492
 
</optgroup>
493
 
</select>
494
 
 
495
 
# NullBooleanSelect Widget ####################################################
496
 
 
497
 
>>> w = NullBooleanSelect()
498
 
>>> print w.render('is_cool', True)
499
 
<select name="is_cool">
500
 
<option value="1">Unknown</option>
501
 
<option value="2" selected="selected">Yes</option>
502
 
<option value="3">No</option>
503
 
</select>
504
 
>>> print w.render('is_cool', False)
505
 
<select name="is_cool">
506
 
<option value="1">Unknown</option>
507
 
<option value="2">Yes</option>
508
 
<option value="3" selected="selected">No</option>
509
 
</select>
510
 
>>> print w.render('is_cool', None)
511
 
<select name="is_cool">
512
 
<option value="1" selected="selected">Unknown</option>
513
 
<option value="2">Yes</option>
514
 
<option value="3">No</option>
515
 
</select>
516
 
>>> print w.render('is_cool', '2')
517
 
<select name="is_cool">
518
 
<option value="1">Unknown</option>
519
 
<option value="2" selected="selected">Yes</option>
520
 
<option value="3">No</option>
521
 
</select>
522
 
>>> print w.render('is_cool', '3')
523
 
<select name="is_cool">
524
 
<option value="1">Unknown</option>
525
 
<option value="2">Yes</option>
526
 
<option value="3" selected="selected">No</option>
527
 
</select>
528
 
 
529
 
""" + \
530
 
r""" # [This concatenation is to keep the string below the jython's 32K limit].
531
 
# SelectMultiple Widget #######################################################
532
 
 
533
 
>>> w = SelectMultiple()
534
 
>>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
535
 
<select multiple="multiple" name="beatles">
536
 
<option value="J" selected="selected">John</option>
537
 
<option value="P">Paul</option>
538
 
<option value="G">George</option>
539
 
<option value="R">Ringo</option>
540
 
</select>
541
 
>>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
542
 
<select multiple="multiple" name="beatles">
543
 
<option value="J" selected="selected">John</option>
544
 
<option value="P" selected="selected">Paul</option>
545
 
<option value="G">George</option>
546
 
<option value="R">Ringo</option>
547
 
</select>
548
 
>>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
549
 
<select multiple="multiple" name="beatles">
550
 
<option value="J" selected="selected">John</option>
551
 
<option value="P" selected="selected">Paul</option>
552
 
<option value="G">George</option>
553
 
<option value="R" selected="selected">Ringo</option>
554
 
</select>
555
 
 
556
 
If the value is None, none of the options are selected:
557
 
>>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
558
 
<select multiple="multiple" name="beatles">
559
 
<option value="J">John</option>
560
 
<option value="P">Paul</option>
561
 
<option value="G">George</option>
562
 
<option value="R">Ringo</option>
563
 
</select>
564
 
 
565
 
If the value corresponds to a label (but not to an option value), none of the options are selected:
566
 
>>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
567
 
<select multiple="multiple" name="beatles">
568
 
<option value="J">John</option>
569
 
<option value="P">Paul</option>
570
 
<option value="G">George</option>
571
 
<option value="R">Ringo</option>
572
 
</select>
573
 
 
574
 
If multiple values are given, but some of them are not valid, the valid ones are selected:
575
 
>>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
576
 
<select multiple="multiple" name="beatles">
577
 
<option value="J" selected="selected">John</option>
578
 
<option value="P">Paul</option>
579
 
<option value="G" selected="selected">George</option>
580
 
<option value="R">Ringo</option>
581
 
</select>
582
 
 
583
 
The value is compared to its str():
584
 
>>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')])
585
 
<select multiple="multiple" name="nums">
586
 
<option value="1">1</option>
587
 
<option value="2" selected="selected">2</option>
588
 
<option value="3">3</option>
589
 
</select>
590
 
>>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)])
591
 
<select multiple="multiple" name="nums">
592
 
<option value="1">1</option>
593
 
<option value="2" selected="selected">2</option>
594
 
<option value="3">3</option>
595
 
</select>
596
 
>>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)])
597
 
<select multiple="multiple" name="nums">
598
 
<option value="1">1</option>
599
 
<option value="2" selected="selected">2</option>
600
 
<option value="3">3</option>
601
 
</select>
602
 
 
603
 
The 'choices' argument can be any iterable:
604
 
>>> def get_choices():
605
 
...     for i in range(5):
606
 
...         yield (i, i)
607
 
>>> print w.render('nums', [2], choices=get_choices())
608
 
<select multiple="multiple" name="nums">
609
 
<option value="0">0</option>
610
 
<option value="1">1</option>
611
 
<option value="2" selected="selected">2</option>
612
 
<option value="3">3</option>
613
 
<option value="4">4</option>
614
 
</select>
615
 
 
616
 
You can also pass 'choices' to the constructor:
617
 
>>> w = SelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
618
 
>>> print w.render('nums', [2])
619
 
<select multiple="multiple" name="nums">
620
 
<option value="1">1</option>
621
 
<option value="2" selected="selected">2</option>
622
 
<option value="3">3</option>
623
 
</select>
624
 
 
625
 
If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
626
 
>>> print w.render('nums', [2], choices=[(4, 4), (5, 5)])
627
 
<select multiple="multiple" name="nums">
628
 
<option value="1">1</option>
629
 
<option value="2" selected="selected">2</option>
630
 
<option value="3">3</option>
631
 
<option value="4">4</option>
632
 
<option value="5">5</option>
633
 
</select>
634
 
 
635
 
# Choices are escaped correctly
636
 
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
637
 
<select multiple="multiple" name="escape">
638
 
<option value="1">1</option>
639
 
<option value="2">2</option>
640
 
<option value="3">3</option>
641
 
<option value="bad">you &amp; me</option>
642
 
<option value="good">you &gt; me</option>
643
 
</select>
644
 
 
645
 
# Unicode choices are correctly rendered as HTML
646
 
>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
647
 
u'<select multiple="multiple" name="nums">\n<option value="1">1</option>\n<option value="2">2</option>\n<option value="3">3</option>\n<option value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" selected="selected">\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</option>\n<option value="\u0107\u017e\u0161\u0111">abc\u0107\u017e\u0161\u0111</option>\n</select>'
648
 
 
649
 
# Test the usage of _has_changed
650
 
>>> w._has_changed(None, None)
651
 
False
652
 
>>> w._has_changed([], None)
653
 
False
654
 
>>> w._has_changed(None, [u'1'])
655
 
True
656
 
>>> w._has_changed([1, 2], [u'1', u'2'])
657
 
False
658
 
>>> w._has_changed([1, 2], [u'1'])
659
 
True
660
 
>>> w._has_changed([1, 2], [u'1', u'3'])
661
 
True
662
 
 
663
 
# Choices can be nested one level in order to create HTML optgroups:
664
 
>>> w.choices = (('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2'))))
665
 
>>> print w.render('nestchoice', None)
666
 
<select multiple="multiple" name="nestchoice">
667
 
<option value="outer1">Outer 1</option>
668
 
<optgroup label="Group &quot;1&quot;">
669
 
<option value="inner1">Inner 1</option>
670
 
<option value="inner2">Inner 2</option>
671
 
</optgroup>
672
 
</select>
673
 
 
674
 
>>> print w.render('nestchoice', ['outer1'])
675
 
<select multiple="multiple" name="nestchoice">
676
 
<option value="outer1" selected="selected">Outer 1</option>
677
 
<optgroup label="Group &quot;1&quot;">
678
 
<option value="inner1">Inner 1</option>
679
 
<option value="inner2">Inner 2</option>
680
 
</optgroup>
681
 
</select>
682
 
 
683
 
>>> print w.render('nestchoice', ['inner1'])
684
 
<select multiple="multiple" name="nestchoice">
685
 
<option value="outer1">Outer 1</option>
686
 
<optgroup label="Group &quot;1&quot;">
687
 
<option value="inner1" selected="selected">Inner 1</option>
688
 
<option value="inner2">Inner 2</option>
689
 
</optgroup>
690
 
</select>
691
 
 
692
 
>>> print w.render('nestchoice', ['outer1', 'inner2'])
693
 
<select multiple="multiple" name="nestchoice">
694
 
<option value="outer1" selected="selected">Outer 1</option>
695
 
<optgroup label="Group &quot;1&quot;">
696
 
<option value="inner1">Inner 1</option>
697
 
<option value="inner2" selected="selected">Inner 2</option>
698
 
</optgroup>
699
 
</select>
700
 
 
701
 
# RadioSelect Widget ##########################################################
702
 
 
703
 
>>> w = RadioSelect()
704
 
>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
705
 
<ul>
706
 
<li><label><input checked="checked" type="radio" name="beatle" value="J" /> John</label></li>
707
 
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
708
 
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
709
 
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
710
 
</ul>
711
 
 
712
 
If the value is None, none of the options are checked:
713
 
>>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
714
 
<ul>
715
 
<li><label><input type="radio" name="beatle" value="J" /> John</label></li>
716
 
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
717
 
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
718
 
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
719
 
</ul>
720
 
 
721
 
If the value corresponds to a label (but not to an option value), none of the options are checked:
722
 
>>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
723
 
<ul>
724
 
<li><label><input type="radio" name="beatle" value="J" /> John</label></li>
725
 
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
726
 
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
727
 
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
728
 
</ul>
729
 
 
730
 
The value is compared to its str():
731
 
>>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
732
 
<ul>
733
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
734
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
735
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
736
 
</ul>
737
 
>>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
738
 
<ul>
739
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
740
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
741
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
742
 
</ul>
743
 
>>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
744
 
<ul>
745
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
746
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
747
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
748
 
</ul>
749
 
 
750
 
The 'choices' argument can be any iterable:
751
 
>>> def get_choices():
752
 
...     for i in range(5):
753
 
...         yield (i, i)
754
 
>>> print w.render('num', 2, choices=get_choices())
755
 
<ul>
756
 
<li><label><input type="radio" name="num" value="0" /> 0</label></li>
757
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
758
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
759
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
760
 
<li><label><input type="radio" name="num" value="4" /> 4</label></li>
761
 
</ul>
762
 
 
763
 
You can also pass 'choices' to the constructor:
764
 
>>> w = RadioSelect(choices=[(1, 1), (2, 2), (3, 3)])
765
 
>>> print w.render('num', 2)
766
 
<ul>
767
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
768
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
769
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
770
 
</ul>
771
 
 
772
 
If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
773
 
>>> print w.render('num', 2, choices=[(4, 4), (5, 5)])
774
 
<ul>
775
 
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
776
 
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
777
 
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
778
 
<li><label><input type="radio" name="num" value="4" /> 4</label></li>
779
 
<li><label><input type="radio" name="num" value="5" /> 5</label></li>
780
 
</ul>
781
 
 
782
 
RadioSelect uses a RadioFieldRenderer to render the individual radio inputs.
783
 
You can manipulate that object directly to customize the way the RadioSelect
784
 
is rendered.
785
 
>>> w = RadioSelect()
786
 
>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
787
 
>>> for inp in r:
788
 
...     print inp
789
 
<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
790
 
<label><input type="radio" name="beatle" value="P" /> Paul</label>
791
 
<label><input type="radio" name="beatle" value="G" /> George</label>
792
 
<label><input type="radio" name="beatle" value="R" /> Ringo</label>
793
 
>>> for inp in r:
794
 
...     print '%s<br />' % inp
795
 
<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label><br />
796
 
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
797
 
<label><input type="radio" name="beatle" value="G" /> George</label><br />
798
 
<label><input type="radio" name="beatle" value="R" /> Ringo</label><br />
799
 
>>> for inp in r:
800
 
...     print '<p>%s %s</p>' % (inp.tag(), inp.choice_label)
801
 
<p><input checked="checked" type="radio" name="beatle" value="J" /> John</p>
802
 
<p><input type="radio" name="beatle" value="P" /> Paul</p>
803
 
<p><input type="radio" name="beatle" value="G" /> George</p>
804
 
<p><input type="radio" name="beatle" value="R" /> Ringo</p>
805
 
>>> for inp in r:
806
 
...     print '%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked())
807
 
beatle J J John True
808
 
beatle J P Paul False
809
 
beatle J G George False
810
 
beatle J R Ringo False
811
 
 
812
 
You can create your own custom renderers for RadioSelect to use.
813
 
>>> class MyRenderer(RadioFieldRenderer):
814
 
...    def render(self):
815
 
...        return u'<br />\n'.join([unicode(choice) for choice in self])
816
 
>>> w = RadioSelect(renderer=MyRenderer)
817
 
>>> print w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
818
 
<label><input type="radio" name="beatle" value="J" /> John</label><br />
819
 
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
820
 
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
821
 
<label><input type="radio" name="beatle" value="R" /> Ringo</label>
822
 
 
823
 
Or you can use custom RadioSelect fields that use your custom renderer.
824
 
>>> class CustomRadioSelect(RadioSelect):
825
 
...    renderer = MyRenderer
826
 
>>> w = CustomRadioSelect()
827
 
>>> print w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
828
 
<label><input type="radio" name="beatle" value="J" /> John</label><br />
829
 
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
830
 
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
831
 
<label><input type="radio" name="beatle" value="R" /> Ringo</label>
832
 
 
833
 
A RadioFieldRenderer object also allows index access to individual RadioInput
834
 
objects.
835
 
>>> w = RadioSelect()
836
 
>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
837
 
>>> print r[1]
838
 
<label><input type="radio" name="beatle" value="P" /> Paul</label>
839
 
>>> print r[0]
840
 
<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
841
 
>>> r[0].is_checked()
842
 
True
843
 
>>> r[1].is_checked()
844
 
False
845
 
>>> r[1].name, r[1].value, r[1].choice_value, r[1].choice_label
846
 
('beatle', u'J', u'P', u'Paul')
847
 
>>> r[10] # doctest: +IGNORE_EXCEPTION_DETAIL
848
 
Traceback (most recent call last):
849
 
...
850
 
IndexError: list index out of range
851
 
 
852
 
# Choices are escaped correctly
853
 
>>> w = RadioSelect()
854
 
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
855
 
<ul>
856
 
<li><label><input type="radio" name="escape" value="bad" /> you &amp; me</label></li>
857
 
<li><label><input type="radio" name="escape" value="good" /> you &gt; me</label></li>
858
 
</ul>
859
 
 
860
 
# Unicode choices are correctly rendered as HTML
861
 
>>> w = RadioSelect()
862
 
>>> unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]))
863
 
u'<ul>\n<li><label><input checked="checked" type="radio" name="email" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="radio" name="email" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>'
864
 
 
865
 
# Attributes provided at instantiation are passed to the constituent inputs
866
 
>>> w = RadioSelect(attrs={'id':'foo'})
867
 
>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
868
 
<ul>
869
 
<li><label for="foo_0"><input checked="checked" type="radio" id="foo_0" value="J" name="beatle" /> John</label></li>
870
 
<li><label for="foo_1"><input type="radio" id="foo_1" value="P" name="beatle" /> Paul</label></li>
871
 
<li><label for="foo_2"><input type="radio" id="foo_2" value="G" name="beatle" /> George</label></li>
872
 
<li><label for="foo_3"><input type="radio" id="foo_3" value="R" name="beatle" /> Ringo</label></li>
873
 
</ul>
874
 
 
875
 
# Attributes provided at render-time are passed to the constituent inputs
876
 
>>> w = RadioSelect()
877
 
>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'})
878
 
<ul>
879
 
<li><label for="bar_0"><input checked="checked" type="radio" id="bar_0" value="J" name="beatle" /> John</label></li>
880
 
<li><label for="bar_1"><input type="radio" id="bar_1" value="P" name="beatle" /> Paul</label></li>
881
 
<li><label for="bar_2"><input type="radio" id="bar_2" value="G" name="beatle" /> George</label></li>
882
 
<li><label for="bar_3"><input type="radio" id="bar_3" value="R" name="beatle" /> Ringo</label></li>
883
 
</ul>
884
 
 
885
 
# CheckboxSelectMultiple Widget ###############################################
886
 
 
887
 
>>> w = CheckboxSelectMultiple()
888
 
>>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
889
 
<ul>
890
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
891
 
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
892
 
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
893
 
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
894
 
</ul>
895
 
>>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
896
 
<ul>
897
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
898
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li>
899
 
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
900
 
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
901
 
</ul>
902
 
>>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
903
 
<ul>
904
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
905
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li>
906
 
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
907
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="R" /> Ringo</label></li>
908
 
</ul>
909
 
 
910
 
If the value is None, none of the options are selected:
911
 
>>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
912
 
<ul>
913
 
<li><label><input type="checkbox" name="beatles" value="J" /> John</label></li>
914
 
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
915
 
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
916
 
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
917
 
</ul>
918
 
 
919
 
If the value corresponds to a label (but not to an option value), none of the options are selected:
920
 
>>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
921
 
<ul>
922
 
<li><label><input type="checkbox" name="beatles" value="J" /> John</label></li>
923
 
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
924
 
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
925
 
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
926
 
</ul>
927
 
 
928
 
If multiple values are given, but some of them are not valid, the valid ones are selected:
929
 
>>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
930
 
<ul>
931
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
932
 
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
933
 
<li><label><input checked="checked" type="checkbox" name="beatles" value="G" /> George</label></li>
934
 
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
935
 
</ul>
936
 
 
937
 
The value is compared to its str():
938
 
>>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')])
939
 
<ul>
940
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
941
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
942
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
943
 
</ul>
944
 
>>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)])
945
 
<ul>
946
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
947
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
948
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
949
 
</ul>
950
 
>>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)])
951
 
<ul>
952
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
953
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
954
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
955
 
</ul>
956
 
 
957
 
The 'choices' argument can be any iterable:
958
 
>>> def get_choices():
959
 
...     for i in range(5):
960
 
...         yield (i, i)
961
 
>>> print w.render('nums', [2], choices=get_choices())
962
 
<ul>
963
 
<li><label><input type="checkbox" name="nums" value="0" /> 0</label></li>
964
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
965
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
966
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
967
 
<li><label><input type="checkbox" name="nums" value="4" /> 4</label></li>
968
 
</ul>
969
 
 
970
 
You can also pass 'choices' to the constructor:
971
 
>>> w = CheckboxSelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
972
 
>>> print w.render('nums', [2])
973
 
<ul>
974
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
975
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
976
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
977
 
</ul>
978
 
 
979
 
If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
980
 
>>> print w.render('nums', [2], choices=[(4, 4), (5, 5)])
981
 
<ul>
982
 
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
983
 
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
984
 
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
985
 
<li><label><input type="checkbox" name="nums" value="4" /> 4</label></li>
986
 
<li><label><input type="checkbox" name="nums" value="5" /> 5</label></li>
987
 
</ul>
988
 
 
989
 
# Choices are escaped correctly
990
 
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you &gt; me'))))
991
 
<ul>
992
 
<li><label><input type="checkbox" name="escape" value="1" /> 1</label></li>
993
 
<li><label><input type="checkbox" name="escape" value="2" /> 2</label></li>
994
 
<li><label><input type="checkbox" name="escape" value="3" /> 3</label></li>
995
 
<li><label><input type="checkbox" name="escape" value="bad" /> you &amp; me</label></li>
996
 
<li><label><input type="checkbox" name="escape" value="good" /> you &gt; me</label></li>
997
 
</ul>
998
 
 
999
 
# Test the usage of _has_changed
1000
 
>>> w._has_changed(None, None)
1001
 
False
1002
 
>>> w._has_changed([], None)
1003
 
False
1004
 
>>> w._has_changed(None, [u'1'])
1005
 
True
1006
 
>>> w._has_changed([1, 2], [u'1', u'2'])
1007
 
False
1008
 
>>> w._has_changed([1, 2], [u'1'])
1009
 
True
1010
 
>>> w._has_changed([1, 2], [u'1', u'3'])
1011
 
True
1012
 
 
1013
 
# Unicode choices are correctly rendered as HTML
1014
 
>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
1015
 
u'<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>'
1016
 
 
1017
 
# MultiWidget #################################################################
1018
 
 
1019
 
>>> class MyMultiWidget(MultiWidget):
1020
 
...     def decompress(self, value):
1021
 
...         if value:
1022
 
...             return value.split('__')
1023
 
...         return ['', '']
1024
 
...     def format_output(self, rendered_widgets):
1025
 
...         return u'<br />'.join(rendered_widgets)
1026
 
>>> w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})))
1027
 
>>> w.render('name', ['john', 'lennon'])
1028
 
u'<input type="text" class="big" value="john" name="name_0" /><br /><input type="text" class="small" value="lennon" name="name_1" />'
1029
 
>>> w.render('name', 'john__lennon')
1030
 
u'<input type="text" class="big" value="john" name="name_0" /><br /><input type="text" class="small" value="lennon" name="name_1" />'
1031
 
>>> w.render('name', 'john__lennon', attrs={'id':'foo'})
1032
 
u'<input id="foo_0" type="text" class="big" value="john" name="name_0" /><br /><input id="foo_1" type="text" class="small" value="lennon" name="name_1" />'
1033
 
>>> w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})), attrs={'id': 'bar'})
1034
 
>>> w.render('name', ['john', 'lennon'])
1035
 
u'<input id="bar_0" type="text" class="big" value="john" name="name_0" /><br /><input id="bar_1" type="text" class="small" value="lennon" name="name_1" />'
1036
 
 
1037
 
>>> w = MyMultiWidget(widgets=(TextInput(), TextInput()))
1038
 
 
1039
 
# test with no initial data
1040
 
>>> w._has_changed(None, [u'john', u'lennon'])
1041
 
True
1042
 
 
1043
 
# test when the data is the same as initial
1044
 
>>> w._has_changed(u'john__lennon', [u'john', u'lennon'])
1045
 
False
1046
 
 
1047
 
# test when the first widget's data has changed
1048
 
>>> w._has_changed(u'john__lennon', [u'alfred', u'lennon'])
1049
 
True
1050
 
 
1051
 
# test when the last widget's data has changed. this ensures that it is not
1052
 
# short circuiting while testing the widgets.
1053
 
>>> w._has_changed(u'john__lennon', [u'john', u'denver'])
1054
 
True
1055
 
 
1056
 
# SplitDateTimeWidget #########################################################
1057
 
 
1058
 
>>> w = SplitDateTimeWidget()
1059
 
>>> w.render('date', '')
1060
 
u'<input type="text" name="date_0" /><input type="text" name="date_1" />'
1061
 
>>> w.render('date', None)
1062
 
u'<input type="text" name="date_0" /><input type="text" name="date_1" />'
1063
 
>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
1064
 
u'<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />'
1065
 
>>> w.render('date', [datetime.date(2006, 1, 10), datetime.time(7, 30)])
1066
 
u'<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />'
1067
 
 
1068
 
You can also pass 'attrs' to the constructor. In this case, the attrs will be
1069
 
included on both widgets.
1070
 
>>> w = SplitDateTimeWidget(attrs={'class': 'pretty'})
1071
 
>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
1072
 
u'<input type="text" class="pretty" value="2006-01-10" name="date_0" /><input type="text" class="pretty" value="07:30:00" name="date_1" />'
1073
 
 
1074
 
>>> w._has_changed(datetime.datetime(2008, 5, 5, 12, 40, 00), [u'2008-05-05', u'12:40:00'])
1075
 
False
1076
 
>>> w._has_changed(datetime.datetime(2008, 5, 5, 12, 40, 00), [u'2008-05-05', u'12:41:00'])
1077
 
True
1078
 
 
1079
 
# DateTimeInput ###############################################################
1080
 
 
1081
 
>>> w = DateTimeInput()
1082
 
>>> w.render('date', None)
1083
 
u'<input type="text" name="date" />'
1084
 
>>> d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548)
1085
 
>>> print d
1086
 
2007-09-17 12:51:34.482548
1087
 
 
1088
 
The microseconds are trimmed on display, by default.
1089
 
>>> w.render('date', d)
1090
 
u'<input type="text" name="date" value="2007-09-17 12:51:34" />'
1091
 
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34))
1092
 
u'<input type="text" name="date" value="2007-09-17 12:51:34" />'
1093
 
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
1094
 
u'<input type="text" name="date" value="2007-09-17 12:51:00" />'
1095
 
 
1096
 
# TimeInput ###################################################################
1097
 
 
1098
 
>>> w = TimeInput()
1099
 
>>> w.render('time', None)
1100
 
u'<input type="text" name="time" />'
1101
 
>>> t = datetime.time(12, 51, 34, 482548)
1102
 
>>> print t
1103
 
12:51:34.482548
1104
 
 
1105
 
The microseconds are trimmed on display, by default.
1106
 
>>> w.render('time', t)
1107
 
u'<input type="text" name="time" value="12:51:34" />'
1108
 
>>> w.render('time', datetime.time(12, 51, 34))
1109
 
u'<input type="text" name="time" value="12:51:34" />'
1110
 
>>> w.render('time', datetime.time(12, 51))
1111
 
u'<input type="text" name="time" value="12:51:00" />'
1112
 
 
1113
 
We should be able to initialize from a unicode value.
1114
 
>>> w.render('time', u'13:12:11')
1115
 
u'<input type="text" name="time" value="13:12:11" />'
1116
 
 
1117
 
# SplitHiddenDateTimeWidget ###################################################
1118
 
 
1119
 
>>> from django.forms.widgets import SplitHiddenDateTimeWidget
1120
 
 
1121
 
>>> w = SplitHiddenDateTimeWidget()
1122
 
>>> w.render('date', '')
1123
 
u'<input type="hidden" name="date_0" /><input type="hidden" name="date_1" />'
1124
 
>>> w.render('date', d)
1125
 
u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />'
1126
 
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34))
1127
 
u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />'
1128
 
>>> w.render('date', datetime.datetime(2007, 9, 17, 12, 51))
1129
 
u'<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:00" />'
1130
 
 
1131
 
"""
1132