1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
7
from django.contrib.admin.tests import AdminSeleniumWebDriverTestCase
8
from django.core.files.uploadedfile import SimpleUploadedFile
9
from django.core.urlresolvers import reverse
10
from django.forms import *
11
from django.forms.widgets import RadioFieldRenderer
12
from django.utils import formats
13
from django.utils.safestring import mark_safe
14
from django.utils import six
15
from django.utils.translation import activate, deactivate
16
from django.test import TestCase
17
from django.test.utils import override_settings
18
from django.utils.encoding import python_2_unicode_compatible, force_text
20
from ..models import Article
23
class FormsWidgetTestCase(TestCase):
24
# Each Widget class corresponds to an HTML form widget. A Widget knows how to
25
# render itself, given a field name and some data. Widgets don't perform
27
def test_textinput(self):
29
self.assertHTMLEqual(w.render('email', ''), '<input type="text" name="email" />')
30
self.assertHTMLEqual(w.render('email', None), '<input type="text" name="email" />')
31
self.assertHTMLEqual(w.render('email', 'test@example.com'), '<input type="text" name="email" value="test@example.com" />')
32
self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '<input type="text" name="email" value="some "quoted" & ampersanded value" />')
33
self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '<input type="text" name="email" value="test@example.com" class="fun" />')
35
self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '<input type="text" name="email" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" class="fun" />')
37
# You can also pass 'attrs' to the constructor:
38
w = TextInput(attrs={'class': 'fun', 'type': 'email'})
39
self.assertHTMLEqual(w.render('email', ''), '<input type="email" class="fun" name="email" />')
40
self.assertHTMLEqual(w.render('email', 'foo@example.com'), '<input type="email" class="fun" value="foo@example.com" name="email" />')
42
# 'attrs' passed to render() get precedence over those passed to the constructor:
43
w = TextInput(attrs={'class': 'pretty'})
44
self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '<input type="text" class="special" name="email" />')
46
# 'attrs' can be safe-strings if needed)
47
w = TextInput(attrs={'onBlur': mark_safe("function('foo')")})
48
self.assertHTMLEqual(w.render('email', ''), '<input onBlur="function(\'foo\')" type="text" name="email" />')
50
def test_passwordinput(self):
52
self.assertHTMLEqual(w.render('email', ''), '<input type="password" name="email" />')
53
self.assertHTMLEqual(w.render('email', None), '<input type="password" name="email" />')
54
self.assertHTMLEqual(w.render('email', 'secret'), '<input type="password" name="email" />')
56
# The render_value argument lets you specify whether the widget should render
57
# its value. For security reasons, this is off by default.
58
w = PasswordInput(render_value=True)
59
self.assertHTMLEqual(w.render('email', ''), '<input type="password" name="email" />')
60
self.assertHTMLEqual(w.render('email', None), '<input type="password" name="email" />')
61
self.assertHTMLEqual(w.render('email', 'test@example.com'), '<input type="password" name="email" value="test@example.com" />')
62
self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '<input type="password" name="email" value="some "quoted" & ampersanded value" />')
63
self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '<input type="password" name="email" value="test@example.com" class="fun" />')
65
# You can also pass 'attrs' to the constructor:
66
w = PasswordInput(attrs={'class': 'fun'}, render_value=True)
67
self.assertHTMLEqual(w.render('email', ''), '<input type="password" class="fun" name="email" />')
68
self.assertHTMLEqual(w.render('email', 'foo@example.com'), '<input type="password" class="fun" value="foo@example.com" name="email" />')
70
# 'attrs' passed to render() get precedence over those passed to the constructor:
71
w = PasswordInput(attrs={'class': 'pretty'}, render_value=True)
72
self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '<input type="password" class="special" name="email" />')
74
self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '<input type="password" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />')
76
def test_hiddeninput(self):
78
self.assertHTMLEqual(w.render('email', ''), '<input type="hidden" name="email" />')
79
self.assertHTMLEqual(w.render('email', None), '<input type="hidden" name="email" />')
80
self.assertHTMLEqual(w.render('email', 'test@example.com'), '<input type="hidden" name="email" value="test@example.com" />')
81
self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '<input type="hidden" name="email" value="some "quoted" & ampersanded value" />')
82
self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '<input type="hidden" name="email" value="test@example.com" class="fun" />')
84
# You can also pass 'attrs' to the constructor:
85
w = HiddenInput(attrs={'class': 'fun'})
86
self.assertHTMLEqual(w.render('email', ''), '<input type="hidden" class="fun" name="email" />')
87
self.assertHTMLEqual(w.render('email', 'foo@example.com'), '<input type="hidden" class="fun" value="foo@example.com" name="email" />')
89
# 'attrs' passed to render() get precedence over those passed to the constructor:
90
w = HiddenInput(attrs={'class': 'pretty'})
91
self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '<input type="hidden" class="special" name="email" />')
93
self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />')
95
# 'attrs' passed to render() get precedence over those passed to the constructor:
96
w = HiddenInput(attrs={'class': 'pretty'})
97
self.assertHTMLEqual(w.render('email', '', attrs={'class': 'special'}), '<input type="hidden" class="special" name="email" />')
99
# Boolean values are rendered to their string forms ("True" and "False").
101
self.assertHTMLEqual(w.render('get_spam', False), '<input type="hidden" name="get_spam" value="False" />')
102
self.assertHTMLEqual(w.render('get_spam', True), '<input type="hidden" name="get_spam" value="True" />')
104
def test_multiplehiddeninput(self):
105
w = MultipleHiddenInput()
106
self.assertHTMLEqual(w.render('email', []), '')
107
self.assertHTMLEqual(w.render('email', None), '')
108
self.assertHTMLEqual(w.render('email', ['test@example.com']), '<input type="hidden" name="email" value="test@example.com" />')
109
self.assertHTMLEqual(w.render('email', ['some "quoted" & ampersanded value']), '<input type="hidden" name="email" value="some "quoted" & ampersanded value" />')
110
self.assertHTMLEqual(w.render('email', ['test@example.com', 'foo@example.com']), '<input type="hidden" name="email" value="test@example.com" />\n<input type="hidden" name="email" value="foo@example.com" />')
111
self.assertHTMLEqual(w.render('email', ['test@example.com'], attrs={'class': 'fun'}), '<input type="hidden" name="email" value="test@example.com" class="fun" />')
112
self.assertHTMLEqual(w.render('email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'}), '<input type="hidden" name="email" value="test@example.com" class="fun" />\n<input type="hidden" name="email" value="foo@example.com" class="fun" />')
114
# You can also pass 'attrs' to the constructor:
115
w = MultipleHiddenInput(attrs={'class': 'fun'})
116
self.assertHTMLEqual(w.render('email', []), '')
117
self.assertHTMLEqual(w.render('email', ['foo@example.com']), '<input type="hidden" class="fun" value="foo@example.com" name="email" />')
118
self.assertHTMLEqual(w.render('email', ['foo@example.com', 'test@example.com']), '<input type="hidden" class="fun" value="foo@example.com" name="email" />\n<input type="hidden" class="fun" value="test@example.com" name="email" />')
120
# 'attrs' passed to render() get precedence over those passed to the constructor:
121
w = MultipleHiddenInput(attrs={'class': 'pretty'})
122
self.assertHTMLEqual(w.render('email', ['foo@example.com'], attrs={'class': 'special'}), '<input type="hidden" class="special" value="foo@example.com" name="email" />')
124
self.assertHTMLEqual(w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'}), '<input type="hidden" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />')
126
# 'attrs' passed to render() get precedence over those passed to the constructor:
127
w = MultipleHiddenInput(attrs={'class': 'pretty'})
128
self.assertHTMLEqual(w.render('email', ['foo@example.com'], attrs={'class': 'special'}), '<input type="hidden" class="special" value="foo@example.com" name="email" />')
130
# Each input gets a separate ID.
131
w = MultipleHiddenInput()
132
self.assertHTMLEqual(w.render('letters', list('abc'), attrs={'id': 'hideme'}), '<input type="hidden" name="letters" value="a" id="hideme_0" />\n<input type="hidden" name="letters" value="b" id="hideme_1" />\n<input type="hidden" name="letters" value="c" id="hideme_2" />')
134
def test_fileinput(self):
135
# FileInput widgets don't ever show the value, because the old value is of no use
136
# if you are updating the form or if the provided file generated an error.
138
self.assertHTMLEqual(w.render('email', ''), '<input type="file" name="email" />')
139
self.assertHTMLEqual(w.render('email', None), '<input type="file" name="email" />')
140
self.assertHTMLEqual(w.render('email', 'test@example.com'), '<input type="file" name="email" />')
141
self.assertHTMLEqual(w.render('email', 'some "quoted" & ampersanded value'), '<input type="file" name="email" />')
142
self.assertHTMLEqual(w.render('email', 'test@example.com', attrs={'class': 'fun'}), '<input type="file" name="email" class="fun" />')
144
# You can also pass 'attrs' to the constructor:
145
w = FileInput(attrs={'class': 'fun'})
146
self.assertHTMLEqual(w.render('email', ''), '<input type="file" class="fun" name="email" />')
147
self.assertHTMLEqual(w.render('email', 'foo@example.com'), '<input type="file" class="fun" name="email" />')
149
self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '<input type="file" class="fun" name="email" />')
151
def test_textarea(self):
153
self.assertHTMLEqual(w.render('msg', ''), '<textarea rows="10" cols="40" name="msg"></textarea>')
154
self.assertHTMLEqual(w.render('msg', None), '<textarea rows="10" cols="40" name="msg"></textarea>')
155
self.assertHTMLEqual(w.render('msg', 'value'), '<textarea rows="10" cols="40" name="msg">value</textarea>')
156
self.assertHTMLEqual(w.render('msg', 'some "quoted" & ampersanded value'), '<textarea rows="10" cols="40" name="msg">some "quoted" & ampersanded value</textarea>')
157
self.assertHTMLEqual(w.render('msg', mark_safe('pre "quoted" value')), '<textarea rows="10" cols="40" name="msg">pre "quoted" value</textarea>')
158
self.assertHTMLEqual(w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20}), '<textarea class="pretty" rows="20" cols="40" name="msg">value</textarea>')
160
# You can also pass 'attrs' to the constructor:
161
w = Textarea(attrs={'class': 'pretty'})
162
self.assertHTMLEqual(w.render('msg', ''), '<textarea rows="10" cols="40" name="msg" class="pretty"></textarea>')
163
self.assertHTMLEqual(w.render('msg', 'example'), '<textarea rows="10" cols="40" name="msg" class="pretty">example</textarea>')
165
# 'attrs' passed to render() get precedence over those passed to the constructor:
166
w = Textarea(attrs={'class': 'pretty'})
167
self.assertHTMLEqual(w.render('msg', '', attrs={'class': 'special'}), '<textarea rows="10" cols="40" name="msg" class="special"></textarea>')
169
self.assertHTMLEqual(w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}), '<textarea rows="10" cols="40" name="msg" class="fun">\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111</textarea>')
171
def test_checkboxinput(self):
173
self.assertHTMLEqual(w.render('is_cool', ''), '<input type="checkbox" name="is_cool" />')
174
self.assertHTMLEqual(w.render('is_cool', None), '<input type="checkbox" name="is_cool" />')
175
self.assertHTMLEqual(w.render('is_cool', False), '<input type="checkbox" name="is_cool" />')
176
self.assertHTMLEqual(w.render('is_cool', True), '<input checked="checked" type="checkbox" name="is_cool" />')
178
# Using any value that's not in ('', None, False, True) will check the checkbox
179
# and set the 'value' attribute.
180
self.assertHTMLEqual(w.render('is_cool', 'foo'), '<input checked="checked" type="checkbox" name="is_cool" value="foo" />')
182
self.assertHTMLEqual(w.render('is_cool', False, attrs={'class': 'pretty'}), '<input type="checkbox" name="is_cool" class="pretty" />')
184
# regression for #17114
185
self.assertHTMLEqual(w.render('is_cool', 0), '<input checked="checked" type="checkbox" name="is_cool" value="0" />')
186
self.assertHTMLEqual(w.render('is_cool', 1), '<input checked="checked" type="checkbox" name="is_cool" value="1" />')
188
# You can also pass 'attrs' to the constructor:
189
w = CheckboxInput(attrs={'class': 'pretty'})
190
self.assertHTMLEqual(w.render('is_cool', ''), '<input type="checkbox" class="pretty" name="is_cool" />')
192
# 'attrs' passed to render() get precedence over those passed to the constructor:
193
w = CheckboxInput(attrs={'class': 'pretty'})
194
self.assertHTMLEqual(w.render('is_cool', '', attrs={'class': 'special'}), '<input type="checkbox" class="special" name="is_cool" />')
196
# You can pass 'check_test' to the constructor. This is a callable that takes the
197
# value and returns True if the box should be checked.
198
w = CheckboxInput(check_test=lambda value: value.startswith('hello'))
199
self.assertHTMLEqual(w.render('greeting', ''), '<input type="checkbox" name="greeting" />')
200
self.assertHTMLEqual(w.render('greeting', 'hello'), '<input checked="checked" type="checkbox" name="greeting" value="hello" />')
201
self.assertHTMLEqual(w.render('greeting', 'hello there'), '<input checked="checked" type="checkbox" name="greeting" value="hello there" />')
202
self.assertHTMLEqual(w.render('greeting', 'hello & goodbye'), '<input checked="checked" type="checkbox" name="greeting" value="hello & goodbye" />')
204
# Ticket #17888: calling check_test shouldn't swallow exceptions
205
with self.assertRaises(AttributeError):
206
w.render('greeting', True)
208
# The CheckboxInput widget will return False if the key is not found in the data
209
# dictionary (because HTML form submission doesn't send any result for unchecked
211
self.assertFalse(w.value_from_datadict({}, {}, 'testing'))
213
value = w.value_from_datadict({'testing': '0'}, {}, 'testing')
214
self.assertIsInstance(value, bool)
215
self.assertTrue(value)
217
def test_select(self):
219
self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select name="beatle">
220
<option value="J" selected="selected">John</option>
221
<option value="P">Paul</option>
222
<option value="G">George</option>
223
<option value="R">Ringo</option>
226
# If the value is None, none of the options are selected:
227
self.assertHTMLEqual(w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select name="beatle">
228
<option value="J">John</option>
229
<option value="P">Paul</option>
230
<option value="G">George</option>
231
<option value="R">Ringo</option>
234
# If the value corresponds to a label (but not to an option value), none of the options are selected:
235
self.assertHTMLEqual(w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select name="beatle">
236
<option value="J">John</option>
237
<option value="P">Paul</option>
238
<option value="G">George</option>
239
<option value="R">Ringo</option>
242
# Only one option can be selected, see #8103:
243
self.assertHTMLEqual(w.render('choices', '0', choices=(('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra'))), """<select name="choices">
244
<option value="0" selected="selected">0</option>
245
<option value="1">1</option>
246
<option value="2">2</option>
247
<option value="3">3</option>
248
<option value="0">extra</option>
251
# The value is compared to its str():
252
self.assertHTMLEqual(w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]), """<select name="num">
253
<option value="1">1</option>
254
<option value="2" selected="selected">2</option>
255
<option value="3">3</option>
257
self.assertHTMLEqual(w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)]), """<select name="num">
258
<option value="1">1</option>
259
<option value="2" selected="selected">2</option>
260
<option value="3">3</option>
262
self.assertHTMLEqual(w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)]), """<select name="num">
263
<option value="1">1</option>
264
<option value="2" selected="selected">2</option>
265
<option value="3">3</option>
268
# The 'choices' argument can be any iterable:
269
from itertools import chain
273
self.assertHTMLEqual(w.render('num', 2, choices=get_choices()), """<select name="num">
274
<option value="0">0</option>
275
<option value="1">1</option>
276
<option value="2" selected="selected">2</option>
277
<option value="3">3</option>
278
<option value="4">4</option>
280
things = ({'id': 1, 'name': 'And Boom'}, {'id': 2, 'name': 'One More Thing!'})
281
class SomeForm(Form):
282
somechoice = ChoiceField(choices=chain((('', '-'*9),), [(thing['id'], thing['name']) for thing in things]))
284
self.assertHTMLEqual(f.as_table(), '<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>')
285
self.assertHTMLEqual(f.as_table(), '<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>')
286
f = SomeForm({'somechoice': 2})
287
self.assertHTMLEqual(f.as_table(), '<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>')
289
# You can also pass 'choices' to the constructor:
290
w = Select(choices=[(1, 1), (2, 2), (3, 3)])
291
self.assertHTMLEqual(w.render('num', 2), """<select name="num">
292
<option value="1">1</option>
293
<option value="2" selected="selected">2</option>
294
<option value="3">3</option>
297
# If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
298
self.assertHTMLEqual(w.render('num', 2, choices=[(4, 4), (5, 5)]), """<select name="num">
299
<option value="1">1</option>
300
<option value="2" selected="selected">2</option>
301
<option value="3">3</option>
302
<option value="4">4</option>
303
<option value="5">5</option>
306
# Choices are escaped correctly
307
self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """<select name="escape">
308
<option value="1">1</option>
309
<option value="2">2</option>
310
<option value="3">3</option>
311
<option value="bad">you & me</option>
312
<option value="good">you > me</option>
315
# Unicode choices are correctly rendered as HTML
316
self.assertHTMLEqual(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), '<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>')
318
# If choices is passed to the constructor and is a generator, it can be iterated
319
# over multiple times without getting consumed:
320
w = Select(choices=get_choices())
321
self.assertHTMLEqual(w.render('num', 2), """<select name="num">
322
<option value="0">0</option>
323
<option value="1">1</option>
324
<option value="2" selected="selected">2</option>
325
<option value="3">3</option>
326
<option value="4">4</option>
328
self.assertHTMLEqual(w.render('num', 3), """<select name="num">
329
<option value="0">0</option>
330
<option value="1">1</option>
331
<option value="2">2</option>
332
<option value="3" selected="selected">3</option>
333
<option value="4">4</option>
336
# Choices can be nested one level in order to create HTML optgroups:
337
w.choices=(('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2'))))
338
self.assertHTMLEqual(w.render('nestchoice', None), """<select name="nestchoice">
339
<option value="outer1">Outer 1</option>
340
<optgroup label="Group "1"">
341
<option value="inner1">Inner 1</option>
342
<option value="inner2">Inner 2</option>
346
self.assertHTMLEqual(w.render('nestchoice', 'outer1'), """<select name="nestchoice">
347
<option value="outer1" selected="selected">Outer 1</option>
348
<optgroup label="Group "1"">
349
<option value="inner1">Inner 1</option>
350
<option value="inner2">Inner 2</option>
354
self.assertHTMLEqual(w.render('nestchoice', 'inner1'), """<select name="nestchoice">
355
<option value="outer1">Outer 1</option>
356
<optgroup label="Group "1"">
357
<option value="inner1" selected="selected">Inner 1</option>
358
<option value="inner2">Inner 2</option>
362
def test_nullbooleanselect(self):
363
w = NullBooleanSelect()
364
self.assertTrue(w.render('is_cool', True), """<select name="is_cool">
365
<option value="1">Unknown</option>
366
<option value="2" selected="selected">Yes</option>
367
<option value="3">No</option>
369
self.assertHTMLEqual(w.render('is_cool', False), """<select name="is_cool">
370
<option value="1">Unknown</option>
371
<option value="2">Yes</option>
372
<option value="3" selected="selected">No</option>
374
self.assertHTMLEqual(w.render('is_cool', None), """<select name="is_cool">
375
<option value="1" selected="selected">Unknown</option>
376
<option value="2">Yes</option>
377
<option value="3">No</option>
379
self.assertHTMLEqual(w.render('is_cool', '2'), """<select name="is_cool">
380
<option value="1">Unknown</option>
381
<option value="2" selected="selected">Yes</option>
382
<option value="3">No</option>
384
self.assertHTMLEqual(w.render('is_cool', '3'), """<select name="is_cool">
385
<option value="1">Unknown</option>
386
<option value="2">Yes</option>
387
<option value="3" selected="selected">No</option>
390
def test_selectmultiple(self):
392
self.assertHTMLEqual(w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
393
<option value="J" selected="selected">John</option>
394
<option value="P">Paul</option>
395
<option value="G">George</option>
396
<option value="R">Ringo</option>
398
self.assertHTMLEqual(w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
399
<option value="J" selected="selected">John</option>
400
<option value="P" selected="selected">Paul</option>
401
<option value="G">George</option>
402
<option value="R">Ringo</option>
404
self.assertHTMLEqual(w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
405
<option value="J" selected="selected">John</option>
406
<option value="P" selected="selected">Paul</option>
407
<option value="G">George</option>
408
<option value="R" selected="selected">Ringo</option>
411
# If the value is None, none of the options are selected:
412
self.assertHTMLEqual(w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
413
<option value="J">John</option>
414
<option value="P">Paul</option>
415
<option value="G">George</option>
416
<option value="R">Ringo</option>
419
# If the value corresponds to a label (but not to an option value), none of the options are selected:
420
self.assertHTMLEqual(w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
421
<option value="J">John</option>
422
<option value="P">Paul</option>
423
<option value="G">George</option>
424
<option value="R">Ringo</option>
427
# Multiple options (with the same value) can be selected, see #8103:
428
self.assertHTMLEqual(w.render('choices', ['0'], choices=(('0', '0'), ('1', '1'), ('2', '2'), ('3', '3'), ('0', 'extra'))), """<select multiple="multiple" name="choices">
429
<option value="0" selected="selected">0</option>
430
<option value="1">1</option>
431
<option value="2">2</option>
432
<option value="3">3</option>
433
<option value="0" selected="selected">extra</option>
436
# If multiple values are given, but some of them are not valid, the valid ones are selected:
437
self.assertHTMLEqual(w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<select multiple="multiple" name="beatles">
438
<option value="J" selected="selected">John</option>
439
<option value="P">Paul</option>
440
<option value="G" selected="selected">George</option>
441
<option value="R">Ringo</option>
444
# The value is compared to its str():
445
self.assertHTMLEqual(w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]), """<select multiple="multiple" name="nums">
446
<option value="1">1</option>
447
<option value="2" selected="selected">2</option>
448
<option value="3">3</option>
450
self.assertHTMLEqual(w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]), """<select multiple="multiple" name="nums">
451
<option value="1">1</option>
452
<option value="2" selected="selected">2</option>
453
<option value="3">3</option>
455
self.assertHTMLEqual(w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]), """<select multiple="multiple" name="nums">
456
<option value="1">1</option>
457
<option value="2" selected="selected">2</option>
458
<option value="3">3</option>
461
# The 'choices' argument can be any iterable:
465
self.assertHTMLEqual(w.render('nums', [2], choices=get_choices()), """<select multiple="multiple" name="nums">
466
<option value="0">0</option>
467
<option value="1">1</option>
468
<option value="2" selected="selected">2</option>
469
<option value="3">3</option>
470
<option value="4">4</option>
473
# You can also pass 'choices' to the constructor:
474
w = SelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
475
self.assertHTMLEqual(w.render('nums', [2]), """<select multiple="multiple" name="nums">
476
<option value="1">1</option>
477
<option value="2" selected="selected">2</option>
478
<option value="3">3</option>
481
# If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
482
self.assertHTMLEqual(w.render('nums', [2], choices=[(4, 4), (5, 5)]), """<select multiple="multiple" name="nums">
483
<option value="1">1</option>
484
<option value="2" selected="selected">2</option>
485
<option value="3">3</option>
486
<option value="4">4</option>
487
<option value="5">5</option>
490
# Choices are escaped correctly
491
self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """<select multiple="multiple" name="escape">
492
<option value="1">1</option>
493
<option value="2">2</option>
494
<option value="3">3</option>
495
<option value="bad">you & me</option>
496
<option value="good">you > me</option>
499
# Unicode choices are correctly rendered as HTML
500
self.assertHTMLEqual(w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), '<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>')
502
# Choices can be nested one level in order to create HTML optgroups:
503
w.choices = (('outer1', 'Outer 1'), ('Group "1"', (('inner1', 'Inner 1'), ('inner2', 'Inner 2'))))
504
self.assertHTMLEqual(w.render('nestchoice', None), """<select multiple="multiple" name="nestchoice">
505
<option value="outer1">Outer 1</option>
506
<optgroup label="Group "1"">
507
<option value="inner1">Inner 1</option>
508
<option value="inner2">Inner 2</option>
512
self.assertHTMLEqual(w.render('nestchoice', ['outer1']), """<select multiple="multiple" name="nestchoice">
513
<option value="outer1" selected="selected">Outer 1</option>
514
<optgroup label="Group "1"">
515
<option value="inner1">Inner 1</option>
516
<option value="inner2">Inner 2</option>
520
self.assertHTMLEqual(w.render('nestchoice', ['inner1']), """<select multiple="multiple" name="nestchoice">
521
<option value="outer1">Outer 1</option>
522
<optgroup label="Group "1"">
523
<option value="inner1" selected="selected">Inner 1</option>
524
<option value="inner2">Inner 2</option>
528
self.assertHTMLEqual(w.render('nestchoice', ['outer1', 'inner2']), """<select multiple="multiple" name="nestchoice">
529
<option value="outer1" selected="selected">Outer 1</option>
530
<optgroup label="Group "1"">
531
<option value="inner1">Inner 1</option>
532
<option value="inner2" selected="selected">Inner 2</option>
536
def test_radioselect(self):
538
self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
539
<li><label><input checked="checked" type="radio" name="beatle" value="J" /> John</label></li>
540
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
541
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
542
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
545
# If the value is None, none of the options are checked:
546
self.assertHTMLEqual(w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
547
<li><label><input type="radio" name="beatle" value="J" /> John</label></li>
548
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
549
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
550
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
553
# If the value corresponds to a label (but not to an option value), none of the options are checked:
554
self.assertHTMLEqual(w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
555
<li><label><input type="radio" name="beatle" value="J" /> John</label></li>
556
<li><label><input type="radio" name="beatle" value="P" /> Paul</label></li>
557
<li><label><input type="radio" name="beatle" value="G" /> George</label></li>
558
<li><label><input type="radio" name="beatle" value="R" /> Ringo</label></li>
561
# The value is compared to its str():
562
self.assertHTMLEqual(w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')]), """<ul>
563
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
564
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
565
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
567
self.assertHTMLEqual(w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)]), """<ul>
568
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
569
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
570
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
572
self.assertHTMLEqual(w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)]), """<ul>
573
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
574
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
575
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
578
# The 'choices' argument can be any iterable:
582
self.assertHTMLEqual(w.render('num', 2, choices=get_choices()), """<ul>
583
<li><label><input type="radio" name="num" value="0" /> 0</label></li>
584
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
585
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
586
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
587
<li><label><input type="radio" name="num" value="4" /> 4</label></li>
590
# You can also pass 'choices' to the constructor:
591
w = RadioSelect(choices=[(1, 1), (2, 2), (3, 3)])
592
self.assertHTMLEqual(w.render('num', 2), """<ul>
593
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
594
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
595
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
598
# If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
599
self.assertHTMLEqual(w.render('num', 2, choices=[(4, 4), (5, 5)]), """<ul>
600
<li><label><input type="radio" name="num" value="1" /> 1</label></li>
601
<li><label><input checked="checked" type="radio" name="num" value="2" /> 2</label></li>
602
<li><label><input type="radio" name="num" value="3" /> 3</label></li>
603
<li><label><input type="radio" name="num" value="4" /> 4</label></li>
604
<li><label><input type="radio" name="num" value="5" /> 5</label></li>
607
# RadioSelect uses a RadioFieldRenderer to render the individual radio inputs.
608
# You can manipulate that object directly to customize the way the RadioSelect
611
r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
618
inp_set1.append(str(inp))
619
inp_set2.append('%s<br />' % inp)
620
inp_set3.append('<p>%s %s</p>' % (inp.tag(), inp.choice_label))
621
inp_set4.append('%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked()))
623
self.assertHTMLEqual('\n'.join(inp_set1), """<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>
624
<label><input type="radio" name="beatle" value="P" /> Paul</label>
625
<label><input type="radio" name="beatle" value="G" /> George</label>
626
<label><input type="radio" name="beatle" value="R" /> Ringo</label>""")
627
self.assertHTMLEqual('\n'.join(inp_set2), """<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label><br />
628
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
629
<label><input type="radio" name="beatle" value="G" /> George</label><br />
630
<label><input type="radio" name="beatle" value="R" /> Ringo</label><br />""")
631
self.assertHTMLEqual('\n'.join(inp_set3), """<p><input checked="checked" type="radio" name="beatle" value="J" /> John</p>
632
<p><input type="radio" name="beatle" value="P" /> Paul</p>
633
<p><input type="radio" name="beatle" value="G" /> George</p>
634
<p><input type="radio" name="beatle" value="R" /> Ringo</p>""")
635
self.assertHTMLEqual('\n'.join(inp_set4), """beatle J J John True
636
beatle J P Paul False
637
beatle J G George False
638
beatle J R Ringo False""")
640
# You can create your own custom renderers for RadioSelect to use.
641
class MyRenderer(RadioFieldRenderer):
643
return '<br />\n'.join([six.text_type(choice) for choice in self])
644
w = RadioSelect(renderer=MyRenderer)
645
self.assertHTMLEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<label><input type="radio" name="beatle" value="J" /> John</label><br />
646
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
647
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
648
<label><input type="radio" name="beatle" value="R" /> Ringo</label>""")
650
# Or you can use custom RadioSelect fields that use your custom renderer.
651
class CustomRadioSelect(RadioSelect):
652
renderer = MyRenderer
653
w = CustomRadioSelect()
654
self.assertHTMLEqual(w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<label><input type="radio" name="beatle" value="J" /> John</label><br />
655
<label><input type="radio" name="beatle" value="P" /> Paul</label><br />
656
<label><input checked="checked" type="radio" name="beatle" value="G" /> George</label><br />
657
<label><input type="radio" name="beatle" value="R" /> Ringo</label>""")
659
# A RadioFieldRenderer object also allows index access to individual RadioChoiceInput
661
r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
662
self.assertHTMLEqual(str(r[1]), '<label><input type="radio" name="beatle" value="P" /> Paul</label>')
663
self.assertHTMLEqual(str(r[0]), '<label><input checked="checked" type="radio" name="beatle" value="J" /> John</label>')
664
self.assertTrue(r[0].is_checked())
665
self.assertFalse(r[1].is_checked())
666
self.assertEqual((r[1].name, r[1].value, r[1].choice_value, r[1].choice_label), ('beatle', 'J', 'P', 'Paul'))
668
with self.assertRaises(IndexError):
671
# Choices are escaped correctly
673
self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """<ul>
674
<li><label><input type="radio" name="escape" value="bad" /> you & me</label></li>
675
<li><label><input type="radio" name="escape" value="good" /> you > me</label></li>
678
# Unicode choices are correctly rendered as HTML
680
self.assertHTMLEqual(six.text_type(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])), '<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>')
682
# Attributes provided at instantiation are passed to the constituent inputs
683
w = RadioSelect(attrs={'id':'foo'})
684
self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul id="foo">
685
<li><label for="foo_0"><input checked="checked" type="radio" id="foo_0" value="J" name="beatle" /> John</label></li>
686
<li><label for="foo_1"><input type="radio" id="foo_1" value="P" name="beatle" /> Paul</label></li>
687
<li><label for="foo_2"><input type="radio" id="foo_2" value="G" name="beatle" /> George</label></li>
688
<li><label for="foo_3"><input type="radio" id="foo_3" value="R" name="beatle" /> Ringo</label></li>
691
# Attributes provided at render-time are passed to the constituent inputs
693
self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'}), """<ul id="bar">
694
<li><label for="bar_0"><input checked="checked" type="radio" id="bar_0" value="J" name="beatle" /> John</label></li>
695
<li><label for="bar_1"><input type="radio" id="bar_1" value="P" name="beatle" /> Paul</label></li>
696
<li><label for="bar_2"><input type="radio" id="bar_2" value="G" name="beatle" /> George</label></li>
697
<li><label for="bar_3"><input type="radio" id="bar_3" value="R" name="beatle" /> Ringo</label></li>
700
def test_checkboxselectmultiple(self):
701
w = CheckboxSelectMultiple()
702
self.assertHTMLEqual(w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
703
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
704
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
705
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
706
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
708
self.assertHTMLEqual(w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
709
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
710
<li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li>
711
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
712
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
714
self.assertHTMLEqual(w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
715
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
716
<li><label><input checked="checked" type="checkbox" name="beatles" value="P" /> Paul</label></li>
717
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
718
<li><label><input checked="checked" type="checkbox" name="beatles" value="R" /> Ringo</label></li>
721
# If the value is None, none of the options are selected:
722
self.assertHTMLEqual(w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
723
<li><label><input type="checkbox" name="beatles" value="J" /> John</label></li>
724
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
725
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
726
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
729
# If the value corresponds to a label (but not to an option value), none of the options are selected:
730
self.assertHTMLEqual(w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
731
<li><label><input type="checkbox" name="beatles" value="J" /> John</label></li>
732
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
733
<li><label><input type="checkbox" name="beatles" value="G" /> George</label></li>
734
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
737
# If multiple values are given, but some of them are not valid, the valid ones are selected:
738
self.assertHTMLEqual(w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul>
739
<li><label><input checked="checked" type="checkbox" name="beatles" value="J" /> John</label></li>
740
<li><label><input type="checkbox" name="beatles" value="P" /> Paul</label></li>
741
<li><label><input checked="checked" type="checkbox" name="beatles" value="G" /> George</label></li>
742
<li><label><input type="checkbox" name="beatles" value="R" /> Ringo</label></li>
745
# The value is compared to its str():
746
self.assertHTMLEqual(w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')]), """<ul>
747
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
748
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
749
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
751
self.assertHTMLEqual(w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)]), """<ul>
752
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
753
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
754
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
756
self.assertHTMLEqual(w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)]), """<ul>
757
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
758
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
759
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
762
# The 'choices' argument can be any iterable:
766
self.assertHTMLEqual(w.render('nums', [2], choices=get_choices()), """<ul>
767
<li><label><input type="checkbox" name="nums" value="0" /> 0</label></li>
768
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
769
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
770
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
771
<li><label><input type="checkbox" name="nums" value="4" /> 4</label></li>
774
# You can also pass 'choices' to the constructor:
775
w = CheckboxSelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
776
self.assertHTMLEqual(w.render('nums', [2]), """<ul>
777
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
778
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
779
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
782
# If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
783
self.assertHTMLEqual(w.render('nums', [2], choices=[(4, 4), (5, 5)]), """<ul>
784
<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>
785
<li><label><input checked="checked" type="checkbox" name="nums" value="2" /> 2</label></li>
786
<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>
787
<li><label><input type="checkbox" name="nums" value="4" /> 4</label></li>
788
<li><label><input type="checkbox" name="nums" value="5" /> 5</label></li>
791
# Choices are escaped correctly
792
self.assertHTMLEqual(w.render('escape', None, choices=(('bad', 'you & me'), ('good', mark_safe('you > me')))), """<ul>
793
<li><label><input type="checkbox" name="escape" value="1" /> 1</label></li>
794
<li><label><input type="checkbox" name="escape" value="2" /> 2</label></li>
795
<li><label><input type="checkbox" name="escape" value="3" /> 3</label></li>
796
<li><label><input type="checkbox" name="escape" value="bad" /> you & me</label></li>
797
<li><label><input type="checkbox" name="escape" value="good" /> you > me</label></li>
800
# Unicode choices are correctly rendered as HTML
801
self.assertHTMLEqual(w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]), '<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>')
803
# Each input gets a separate ID
804
self.assertHTMLEqual(CheckboxSelectMultiple().render('letters', list('ac'), choices=zip(list('abc'), list('ABC')), attrs={'id': 'abc'}), """<ul id="abc">
805
<li><label for="abc_0"><input checked="checked" type="checkbox" name="letters" value="a" id="abc_0" /> A</label></li>
806
<li><label for="abc_1"><input type="checkbox" name="letters" value="b" id="abc_1" /> B</label></li>
807
<li><label for="abc_2"><input checked="checked" type="checkbox" name="letters" value="c" id="abc_2" /> C</label></li>
810
# Each input gets a separate ID when the ID is passed to the constructor
811
self.assertHTMLEqual(CheckboxSelectMultiple(attrs={'id': 'abc'}).render('letters', list('ac'), choices=zip(list('abc'), list('ABC'))), """<ul id="abc">
812
<li><label for="abc_0"><input checked="checked" type="checkbox" name="letters" value="a" id="abc_0" /> A</label></li>
813
<li><label for="abc_1"><input type="checkbox" name="letters" value="b" id="abc_1" /> B</label></li>
814
<li><label for="abc_2"><input checked="checked" type="checkbox" name="letters" value="c" id="abc_2" /> C</label></li>
817
w = CheckboxSelectMultiple()
818
r = w.get_renderer('abc', 'b', choices=[(c, c.upper()) for c in 'abc'])
819
# You can iterate over the CheckboxFieldRenderer to get individual elements
821
'<label><input type="checkbox" name="abc" value="a" /> A</label>',
822
'<label><input checked="checked" type="checkbox" name="abc" value="b" /> B</label>',
823
'<label><input type="checkbox" name="abc" value="c" /> C</label>',
825
for output, expected in zip(r, expected):
826
self.assertHTMLEqual(force_text(output), expected)
828
# You can access individual elements
829
self.assertHTMLEqual(force_text(r[1]),
830
'<label><input checked="checked" type="checkbox" name="abc" value="b" /> B</label>')
832
# Out-of-range errors are propagated
833
with self.assertRaises(IndexError):
836
def test_multi(self):
837
class MyMultiWidget(MultiWidget):
838
def decompress(self, value):
840
return value.split('__')
842
def format_output(self, rendered_widgets):
843
return '<br />'.join(rendered_widgets)
845
w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})))
846
self.assertHTMLEqual(w.render('name', ['john', 'lennon']), '<input type="text" class="big" value="john" name="name_0" /><br /><input type="text" class="small" value="lennon" name="name_1" />')
847
self.assertHTMLEqual(w.render('name', 'john__lennon'), '<input type="text" class="big" value="john" name="name_0" /><br /><input type="text" class="small" value="lennon" name="name_1" />')
848
self.assertHTMLEqual(w.render('name', 'john__lennon', attrs={'id':'foo'}), '<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" />')
849
w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})), attrs={'id': 'bar'})
850
self.assertHTMLEqual(w.render('name', ['john', 'lennon']), '<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" />')
852
# Test needs_multipart_form=True if any widget needs it
853
w = MyMultiWidget(widgets=(TextInput(), FileInput()))
854
self.assertTrue(w.needs_multipart_form)
856
# Test needs_multipart_form=False if no widget needs it
857
w = MyMultiWidget(widgets=(TextInput(), TextInput()))
858
self.assertFalse(w.needs_multipart_form)
860
def test_splitdatetime(self):
861
w = SplitDateTimeWidget()
862
self.assertHTMLEqual(w.render('date', ''), '<input type="text" name="date_0" /><input type="text" name="date_1" />')
863
self.assertHTMLEqual(w.render('date', None), '<input type="text" name="date_0" /><input type="text" name="date_1" />')
864
self.assertHTMLEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), '<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />')
865
self.assertHTMLEqual(w.render('date', [datetime.date(2006, 1, 10), datetime.time(7, 30)]), '<input type="text" name="date_0" value="2006-01-10" /><input type="text" name="date_1" value="07:30:00" />')
867
# You can also pass 'attrs' to the constructor. In this case, the attrs will be
868
w = SplitDateTimeWidget(attrs={'class': 'pretty'})
869
self.assertHTMLEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), '<input type="text" class="pretty" value="2006-01-10" name="date_0" /><input type="text" class="pretty" value="07:30:00" name="date_1" />')
871
# Use 'date_format' and 'time_format' to change the way a value is displayed.
872
w = SplitDateTimeWidget(date_format='%d/%m/%Y', time_format='%H:%M')
873
self.assertHTMLEqual(w.render('date', datetime.datetime(2006, 1, 10, 7, 30)), '<input type="text" name="date_0" value="10/01/2006" /><input type="text" name="date_1" value="07:30" />')
875
def test_datetimeinput(self):
877
self.assertHTMLEqual(w.render('date', None), '<input type="text" name="date" />')
878
d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548)
879
self.assertEqual(str(d), '2007-09-17 12:51:34.482548')
881
# The microseconds are trimmed on display, by default.
882
self.assertHTMLEqual(w.render('date', d), '<input type="text" name="date" value="2007-09-17 12:51:34" />')
883
self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34)), '<input type="text" name="date" value="2007-09-17 12:51:34" />')
884
self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), '<input type="text" name="date" value="2007-09-17 12:51:00" />')
886
# Use 'format' to change the way a value is displayed.
887
w = DateTimeInput(format='%d/%m/%Y %H:%M', attrs={'type': 'datetime'})
888
self.assertHTMLEqual(w.render('date', d), '<input type="datetime" name="date" value="17/09/2007 12:51" />')
890
def test_dateinput(self):
892
self.assertHTMLEqual(w.render('date', None), '<input type="text" name="date" />')
893
d = datetime.date(2007, 9, 17)
894
self.assertEqual(str(d), '2007-09-17')
896
self.assertHTMLEqual(w.render('date', d), '<input type="text" name="date" value="2007-09-17" />')
897
self.assertHTMLEqual(w.render('date', datetime.date(2007, 9, 17)), '<input type="text" name="date" value="2007-09-17" />')
899
# We should be able to initialize from a unicode value.
900
self.assertHTMLEqual(w.render('date', '2007-09-17'), '<input type="text" name="date" value="2007-09-17" />')
902
# Use 'format' to change the way a value is displayed.
903
w = DateInput(format='%d/%m/%Y', attrs={'type': 'date'})
904
self.assertHTMLEqual(w.render('date', d), '<input type="date" name="date" value="17/09/2007" />')
906
def test_timeinput(self):
908
self.assertHTMLEqual(w.render('time', None), '<input type="text" name="time" />')
909
t = datetime.time(12, 51, 34, 482548)
910
self.assertEqual(str(t), '12:51:34.482548')
912
# The microseconds are trimmed on display, by default.
913
self.assertHTMLEqual(w.render('time', t), '<input type="text" name="time" value="12:51:34" />')
914
self.assertHTMLEqual(w.render('time', datetime.time(12, 51, 34)), '<input type="text" name="time" value="12:51:34" />')
915
self.assertHTMLEqual(w.render('time', datetime.time(12, 51)), '<input type="text" name="time" value="12:51:00" />')
917
# We should be able to initialize from a unicode value.
918
self.assertHTMLEqual(w.render('time', '13:12:11'), '<input type="text" name="time" value="13:12:11" />')
920
# Use 'format' to change the way a value is displayed.
921
w = TimeInput(format='%H:%M', attrs={'type': 'time'})
922
self.assertHTMLEqual(w.render('time', t), '<input type="time" name="time" value="12:51" />')
924
def test_splithiddendatetime(self):
925
from django.forms.widgets import SplitHiddenDateTimeWidget
927
w = SplitHiddenDateTimeWidget()
928
self.assertHTMLEqual(w.render('date', ''), '<input type="hidden" name="date_0" /><input type="hidden" name="date_1" />')
929
d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548)
930
self.assertHTMLEqual(str(d), '2007-09-17 12:51:34.482548')
931
self.assertHTMLEqual(w.render('date', d), '<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />')
932
self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51, 34)), '<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:34" />')
933
self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), '<input type="hidden" name="date_0" value="2007-09-17" /><input type="hidden" name="date_1" value="12:51:00" />')
936
class NullBooleanSelectLazyForm(Form):
937
"""Form to test for lazy evaluation. Refs #17190"""
938
bool = BooleanField(widget=NullBooleanSelect())
940
@override_settings(USE_L10N=True)
941
class FormsI18NWidgetsTestCase(TestCase):
943
super(FormsI18NWidgetsTestCase, self).setUp()
948
super(FormsI18NWidgetsTestCase, self).tearDown()
950
def test_datetimeinput(self):
952
d = datetime.datetime(2007, 9, 17, 12, 51, 34, 482548)
953
w.is_localized = True
954
self.assertHTMLEqual(w.render('date', d), '<input type="text" name="date" value="17.09.2007 12:51:34" />')
956
def test_dateinput(self):
958
d = datetime.date(2007, 9, 17)
959
w.is_localized = True
960
self.assertHTMLEqual(w.render('date', d), '<input type="text" name="date" value="17.09.2007" />')
962
def test_timeinput(self):
964
t = datetime.time(12, 51, 34, 482548)
965
w.is_localized = True
966
self.assertHTMLEqual(w.render('time', t), '<input type="text" name="time" value="12:51:34" />')
968
def test_splithiddendatetime(self):
969
from django.forms.widgets import SplitHiddenDateTimeWidget
971
w = SplitHiddenDateTimeWidget()
972
w.is_localized = True
973
self.assertHTMLEqual(w.render('date', datetime.datetime(2007, 9, 17, 12, 51)), '<input type="hidden" name="date_0" value="17.09.2007" /><input type="hidden" name="date_1" value="12:51:00" />')
975
def test_nullbooleanselect(self):
977
Ensure that the NullBooleanSelect widget's options are lazily
981
f = NullBooleanSelectLazyForm()
982
self.assertHTMLEqual(f.fields['bool'].widget.render('id_bool', True), '<select name="id_bool">\n<option value="1">Unbekannt</option>\n<option value="2" selected="selected">Ja</option>\n<option value="3">Nein</option>\n</select>')
985
class SelectAndTextWidget(MultiWidget):
989
def __init__(self, choices=[]):
991
RadioSelect(choices=choices),
994
super(SelectAndTextWidget, self).__init__(widgets)
996
def _set_choices(self, choices):
998
When choices are set for this widget, we want to pass those along to the Select widget
1000
self.widgets[0].choices = choices
1001
def _get_choices(self):
1003
The choices for this widget are the Select widget's choices
1005
return self.widgets[0].choices
1006
choices = property(_get_choices, _set_choices)
1009
class WidgetTests(TestCase):
1010
def test_12048(self):
1011
# See ticket #12048.
1012
w1 = SelectAndTextWidget(choices=[1,2,3])
1013
w2 = copy.deepcopy(w1)
1014
w2.choices = [4,5,6]
1015
# w2 ought to be independent of w1, since MultiWidget ought
1016
# to make a copy of its sub-widgets when it is copied.
1017
self.assertEqual(w1.choices, [1,2,3])
1019
def test_13390(self):
1021
class SplitDateForm(Form):
1022
field = DateTimeField(widget=SplitDateTimeWidget, required=False)
1024
form = SplitDateForm({'field': ''})
1025
self.assertTrue(form.is_valid())
1026
form = SplitDateForm({'field': ['', '']})
1027
self.assertTrue(form.is_valid())
1029
class SplitDateRequiredForm(Form):
1030
field = DateTimeField(widget=SplitDateTimeWidget, required=True)
1032
form = SplitDateRequiredForm({'field': ''})
1033
self.assertFalse(form.is_valid())
1034
form = SplitDateRequiredForm({'field': ['', '']})
1035
self.assertFalse(form.is_valid())
1038
class LiveWidgetTests(AdminSeleniumWebDriverTestCase):
1040
available_apps = ['forms_tests'] + AdminSeleniumWebDriverTestCase.available_apps
1041
urls = 'forms_tests.urls'
1043
def test_textarea_trailing_newlines(self):
1045
Test that a roundtrip on a ModelForm doesn't alter the TextField value
1047
article = Article.objects.create(content="\nTst\n")
1048
self.selenium.get('%s%s' % (self.live_server_url,
1049
reverse('article_form', args=[article.pk])))
1050
self.selenium.find_element_by_id('submit').submit()
1051
article = Article.objects.get(pk=article.pk)
1052
# Should be "\nTst\n" after #19251 is fixed
1053
self.assertEqual(article.content, "\r\nTst\r\n")
1056
@python_2_unicode_compatible
1057
class FakeFieldFile(object):
1059
Quacks like a FieldFile (has a .url and unicode representation), but
1060
doesn't require us to care about storages etc.
1068
class ClearableFileInputTests(TestCase):
1069
def test_clear_input_renders(self):
1071
A ClearableFileInput with is_required False and rendered with
1072
an initial value that is a file renders a clear checkbox.
1075
widget = ClearableFileInput()
1076
widget.is_required = False
1077
self.assertHTMLEqual(widget.render('myfile', FakeFieldFile()),
1078
'Currently: <a href="something">something</a> <input type="checkbox" name="myfile-clear" id="myfile-clear_id" /> <label for="myfile-clear_id">Clear</label><br />Change: <input type="file" name="myfile" />')
1080
def test_html_escaped(self):
1082
A ClearableFileInput should escape name, filename and URL when
1083
rendering HTML. Refs #15182.
1086
@python_2_unicode_compatible
1087
class StrangeFieldFile(object):
1088
url = "something?chapter=1§=2©=3&lang=en"
1091
return '''something<div onclick="alert('oops')">.jpg'''
1093
widget = ClearableFileInput()
1094
field = StrangeFieldFile()
1095
output = widget.render('my<div>file', field)
1096
self.assertFalse(field.url in output)
1097
self.assertTrue('href="something?chapter=1&sect=2&copy=3&lang=en"' in output)
1098
self.assertFalse(six.text_type(field) in output)
1099
self.assertTrue('something<div onclick="alert('oops')">.jpg' in output)
1100
self.assertTrue('my<div>file' in output)
1101
self.assertFalse('my<div>file' in output)
1103
def test_clear_input_renders_only_if_not_required(self):
1105
A ClearableFileInput with is_required=False does not render a clear
1109
widget = ClearableFileInput()
1110
widget.is_required = True
1111
self.assertHTMLEqual(widget.render('myfile', FakeFieldFile()),
1112
'Currently: <a href="something">something</a> <br />Change: <input type="file" name="myfile" />')
1114
def test_clear_input_renders_only_if_initial(self):
1116
A ClearableFileInput instantiated with no initial value does not render
1120
widget = ClearableFileInput()
1121
widget.is_required = False
1122
self.assertHTMLEqual(widget.render('myfile', None),
1123
'<input type="file" name="myfile" />')
1125
def test_clear_input_checked_returns_false(self):
1127
ClearableFileInput.value_from_datadict returns False if the clear
1128
checkbox is checked, if not required.
1131
widget = ClearableFileInput()
1132
widget.is_required = False
1133
self.assertEqual(widget.value_from_datadict(
1134
data={'myfile-clear': True},
1136
name='myfile'), False)
1138
def test_clear_input_checked_returns_false_only_if_not_required(self):
1140
ClearableFileInput.value_from_datadict never returns False if the field
1144
widget = ClearableFileInput()
1145
widget.is_required = True
1146
f = SimpleUploadedFile('something.txt', b'content')
1147
self.assertEqual(widget.value_from_datadict(
1148
data={'myfile-clear': True},
1149
files={'myfile': f},