1
# -*- coding: utf-8 -*-
3
>>> from django.forms import *
4
>>> from django.forms.widgets import RadioFieldRenderer
5
>>> from django.utils.safestring import mark_safe
10
... from decimal import Decimal
11
... except ImportError:
12
... from django.utils._decimal import Decimal
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
22
# TextInput Widget ############################################################
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 "quoted" & 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" />'
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" />'
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" />'
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" />'
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" />
58
# PasswordInput Widget ############################################################
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 "quoted" & 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" />'
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" />'
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" />'
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" />'
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" />'
103
# HiddenInput Widget ############################################################
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 "quoted" & 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" />'
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" />'
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" />'
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" />'
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" />'
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" />'
144
# MultipleHiddenInput Widget ##################################################
146
>>> w = MultipleHiddenInput()
147
>>> w.render('email', [])
149
>>> w.render('email', None)
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 "quoted" & 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" />'
162
You can also pass 'attrs' to the constructor:
163
>>> w = MultipleHiddenInput(attrs={'class': 'fun'})
164
>>> w.render('email', [])
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" />'
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" />'
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" />'
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" />'
184
# FileInput Widget ############################################################
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.
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" />'
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" />'
207
>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
208
u'<input type="file" class="fun" name="email" />'
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.
217
# No file was uploaded and no initial data.
218
>>> w._has_changed(u'', None)
221
# A file was uploaded and no initial data.
222
>>> w._has_changed(u'', {'filename': 'resume.txt', 'content': 'My resume'})
225
# A file was not uploaded, but there is initial data
226
>>> w._has_changed(u'resume.txt', None)
229
# A file was uploaded and there is initial data (file identity is not dealt
231
>>> w._has_changed('resume.txt', {'filename': 'resume.txt', 'content': 'My resume'})
234
# Textarea Widget #############################################################
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 "quoted" & ampersanded value</textarea>'
245
>>> w.render('msg', mark_safe('pre "quoted" value'))
246
u'<textarea rows="10" cols="40" name="msg">pre "quoted" 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>'
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>'
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>'
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>'
265
# CheckboxInput Widget ########################################################
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" />'
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" />'
282
>>> w.render('is_cool', False, attrs={'class': 'pretty'})
283
u'<input type="checkbox" name="is_cool" class="pretty" />'
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" />'
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" />'
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 & goodbye" />'
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" />'
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
321
>>> w.value_from_datadict({}, {}, 'testing')
324
>>> w._has_changed(None, None)
326
>>> w._has_changed(None, u'')
328
>>> w._has_changed(u'', None)
330
>>> w._has_changed(u'', u'')
332
>>> w._has_changed(False, u'on')
334
>>> w._has_changed(True, u'on')
336
>>> w._has_changed(True, u'')
339
# Select Widget ###############################################################
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>
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>
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>
368
The value is compared to its str():
369
>>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
371
<option value="1">1</option>
372
<option value="2" selected="selected">2</option>
373
<option value="3">3</option>
375
>>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
377
<option value="1">1</option>
378
<option value="2" selected="selected">2</option>
379
<option value="3">3</option>
381
>>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
383
<option value="1">1</option>
384
<option value="2" selected="selected">2</option>
385
<option value="3">3</option>
388
The 'choices' argument can be any iterable:
389
>>> from itertools import chain
390
>>> def get_choices():
391
... for i in range(5):
393
>>> print w.render('num', 2, choices=get_choices())
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>
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]))
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>'
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})
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>'
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)
417
<option value="1">1</option>
418
<option value="2" selected="selected">2</option>
419
<option value="3">3</option>
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)])
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>
432
# Choices are escaped correctly
433
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > 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 & me</option>
439
<option value="good">you > me</option>
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>'
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)
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>
457
>>> print w.render('num', 3)
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>
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 "1"">
472
<option value="inner1">Inner 1</option>
473
<option value="inner2">Inner 2</option>
477
>>> print w.render('nestchoice', 'outer1')
478
<select name="nestchoice">
479
<option value="outer1" selected="selected">Outer 1</option>
480
<optgroup label="Group "1"">
481
<option value="inner1">Inner 1</option>
482
<option value="inner2">Inner 2</option>
486
>>> print w.render('nestchoice', 'inner1')
487
<select name="nestchoice">
488
<option value="outer1">Outer 1</option>
489
<optgroup label="Group "1"">
490
<option value="inner1" selected="selected">Inner 1</option>
491
<option value="inner2">Inner 2</option>
495
# NullBooleanSelect Widget ####################################################
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>
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>
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>
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>
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>
530
r""" # [This concatenation is to keep the string below the jython's 32K limit].
531
# SelectMultiple Widget #######################################################
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>
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>
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>
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>
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>
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>
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>
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>
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>
603
The 'choices' argument can be any iterable:
604
>>> def get_choices():
605
... for i in range(5):
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>
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>
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>
635
# Choices are escaped correctly
636
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > 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 & me</option>
642
<option value="good">you > me</option>
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>'
649
# Test the usage of _has_changed
650
>>> w._has_changed(None, None)
652
>>> w._has_changed([], None)
654
>>> w._has_changed(None, [u'1'])
656
>>> w._has_changed([1, 2], [u'1', u'2'])
658
>>> w._has_changed([1, 2], [u'1'])
660
>>> w._has_changed([1, 2], [u'1', u'3'])
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 "1"">
669
<option value="inner1">Inner 1</option>
670
<option value="inner2">Inner 2</option>
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 "1"">
678
<option value="inner1">Inner 1</option>
679
<option value="inner2">Inner 2</option>
683
>>> print w.render('nestchoice', ['inner1'])
684
<select multiple="multiple" name="nestchoice">
685
<option value="outer1">Outer 1</option>
686
<optgroup label="Group "1"">
687
<option value="inner1" selected="selected">Inner 1</option>
688
<option value="inner2">Inner 2</option>
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 "1"">
696
<option value="inner1">Inner 1</option>
697
<option value="inner2" selected="selected">Inner 2</option>
701
# RadioSelect Widget ##########################################################
703
>>> w = RadioSelect()
704
>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
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>
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')))
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>
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')))
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>
730
The value is compared to its str():
731
>>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
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>
737
>>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
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>
743
>>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
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>
750
The 'choices' argument can be any iterable:
751
>>> def get_choices():
752
... for i in range(5):
754
>>> print w.render('num', 2, choices=get_choices())
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>
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)
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>
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)])
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>
782
RadioSelect uses a RadioFieldRenderer to render the individual radio inputs.
783
You can manipulate that object directly to customize the way the RadioSelect
785
>>> w = RadioSelect()
786
>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
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>
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 />
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>
806
... print '%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked())
808
beatle J P Paul False
809
beatle J G George False
810
beatle J R Ringo False
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>
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>
833
A RadioFieldRenderer object also allows index access to individual RadioInput
835
>>> w = RadioSelect()
836
>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
838
<label><input type="radio" name="beatle" value="P" /> Paul</label>
840
<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
841
>>> r[0].is_checked()
843
>>> r[1].is_checked()
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):
850
IndexError: list index out of range
852
# Choices are escaped correctly
853
>>> w = RadioSelect()
854
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me'))))
856
<li><label><input type="radio" name="escape" value="bad" /> you & me</label></li>
857
<li><label><input type="radio" name="escape" value="good" /> you > me</label></li>
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>'
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')))
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>
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'})
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>
885
# CheckboxSelectMultiple Widget ###############################################
887
>>> w = CheckboxSelectMultiple()
888
>>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
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>
895
>>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
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>
902
>>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
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>
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')))
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>
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')))
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>
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')))
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>
937
The value is compared to its str():
938
>>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')])
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>
944
>>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)])
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>
950
>>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)])
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>
957
The 'choices' argument can be any iterable:
958
>>> def get_choices():
959
... for i in range(5):
961
>>> print w.render('nums', [2], choices=get_choices())
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>
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])
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>
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)])
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>
989
# Choices are escaped correctly
990
>>> print w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me'))))
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 & me</label></li>
996
<li><label><input type="checkbox" name="escape" value="good" /> you > me</label></li>
999
# Test the usage of _has_changed
1000
>>> w._has_changed(None, None)
1002
>>> w._has_changed([], None)
1004
>>> w._has_changed(None, [u'1'])
1006
>>> w._has_changed([1, 2], [u'1', u'2'])
1008
>>> w._has_changed([1, 2], [u'1'])
1010
>>> w._has_changed([1, 2], [u'1', u'3'])
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>'
1017
# MultiWidget #################################################################
1019
>>> class MyMultiWidget(MultiWidget):
1020
... def decompress(self, value):
1022
... return value.split('__')
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" />'
1037
>>> w = MyMultiWidget(widgets=(TextInput(), TextInput()))
1039
# test with no initial data
1040
>>> w._has_changed(None, [u'john', u'lennon'])
1043
# test when the data is the same as initial
1044
>>> w._has_changed(u'john__lennon', [u'john', u'lennon'])
1047
# test when the first widget's data has changed
1048
>>> w._has_changed(u'john__lennon', [u'alfred', u'lennon'])
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'])
1056
# SplitDateTimeWidget #########################################################
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" />'
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" />'
1074
>>> w._has_changed(datetime.datetime(2008, 5, 5, 12, 40, 00), [u'2008-05-05', u'12:40:00'])
1076
>>> w._has_changed(datetime.datetime(2008, 5, 5, 12, 40, 00), [u'2008-05-05', u'12:41:00'])
1079
# DateTimeInput ###############################################################
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)
1086
2007-09-17 12:51:34.482548
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" />'
1096
# TimeInput ###################################################################
1099
>>> w.render('time', None)
1100
u'<input type="text" name="time" />'
1101
>>> t = datetime.time(12, 51, 34, 482548)
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" />'
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" />'
1117
# SplitHiddenDateTimeWidget ###################################################
1119
>>> from django.forms.widgets import SplitHiddenDateTimeWidget
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" />'