Refs #32338 -- Made RadioSelect/CheckboxSelectMultiple render in <div> tags.

This improves accessibility for screen reader users.
This commit is contained in:
David Smith 2021-06-11 07:39:12 +01:00 committed by Mariusz Felisiak
parent a5cb1ef6eb
commit 5942ab5eb1
9 changed files with 258 additions and 264 deletions

View File

@ -1,5 +1,5 @@
{% set id = widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>{% for group, options, index in widget.optgroups %}{% if group %}
<li>{{ group }}<ul{% if id %} id="{{ id }}_{{ index }}"{% endif %}>{% endif %}{% for widget in options %}
<li>{% include widget.template_name %}</li>{% endfor %}{% if group %}
</ul></li>{% endif %}{% endfor %}
</ul>
{% set id = widget.attrs.id %}<div{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>{% for group, options, index in widget.optgroups %}{% if group %}
<div><label>{{ group }}</label>{% endif %}{% for widget in options %}<div>
{% include widget.template_name %}</div>{% endfor %}{% if group %}
</div>{% endif %}{% endfor %}
</div>

View File

@ -1,5 +1,5 @@
{% with id=widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>{% for group, options, index in widget.optgroups %}{% if group %}
<li>{{ group }}<ul{% if id %} id="{{ id }}_{{ index }}"{% endif %}>{% endif %}{% for option in options %}
<li>{% include option.template_name with widget=option %}</li>{% endfor %}{% if group %}
</ul></li>{% endif %}{% endfor %}
</ul>{% endwith %}
{% with id=widget.attrs.id %}<div{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>{% for group, options, index in widget.optgroups %}{% if group %}
<div><label>{{ group }}</label>{% endif %}{% for option in options %}<div>
{% include option.template_name with widget=option %}</div>{% endfor %}{% if group %}
</div>{% endif %}{% endfor %}
</div>{% endwith %}

View File

@ -703,14 +703,19 @@ that specifies the template used to render each choice. For example, for the
* ``option_template_name``: ``'django/forms/widgets/radio_option.html'``
Similar to :class:`Select`, but rendered as a list of radio buttons within
``<li>`` tags:
``<div>`` tags:
.. code-block:: html
<ul>
<li><input type="radio" name="..."></li>
<div>
<div><input type="radio" name="..."></div>
...
</ul>
</div>
.. versionchanged:: 4.0
So they are announced more concisely by screen readers, radio buttons
were changed to render in ``<div>`` tags.
For more granular control over the generated markup, you can loop over the
radio buttons in the template. Assuming a form ``myform`` with a field
@ -788,10 +793,10 @@ that specifies the template used to render each choice. For example, for the
</fieldset>
If you decide not to loop over the radio buttons -- e.g., if your template
includes ``{{ myform.beatles }}`` -- they'll be output in a ``<ul>`` with
``<li>`` tags, as above.
includes ``{{ myform.beatles }}`` -- they'll be output in a ``<div>`` with
``<div>`` tags, as above.
The outer ``<ul>`` container receives the ``id`` attribute of the widget,
The outer ``<div>`` container receives the ``id`` attribute of the widget,
if defined, or :attr:`BoundField.auto_id` otherwise.
When looping over the radio buttons, the ``label`` and ``input`` tags include
@ -810,14 +815,19 @@ that specifies the template used to render each choice. For example, for the
.. code-block:: html
<ul>
<li><input type="checkbox" name="..." ></li>
<div>
<div><input type="checkbox" name="..." ></div>
...
</ul>
</div>
The outer ``<ul>`` container receives the ``id`` attribute of the widget,
The outer ``<div>`` container receives the ``id`` attribute of the widget,
if defined, or :attr:`BoundField.auto_id` otherwise.
.. versionchanged:: 4.0
So they are announced more concisely by screen readers, checkboxes were
changed to render in ``<div>`` tags.
Like :class:`RadioSelect`, you can loop over the individual checkboxes for the
widget's choices. Unlike :class:`RadioSelect`, the checkboxes won't include the
``required`` HTML attribute if the field is required because browser validation

View File

@ -551,6 +551,13 @@ Miscellaneous
``django.db.migrations.state.ProjectState.__init__()`` method must now be a
set if provided.
* :class:`~django.forms.RadioSelect` and
:class:`~django.forms.CheckboxSelectMultiple` widgets are now rendered in
``<div>`` tags so they are announced more concisely by screen readers. If you
need the previous behavior, :ref:`override the widget template
<overriding-built-in-widget-templates>` with the appropriate template from
Django 3.2.
.. _deprecated-features-4.0:
Features deprecated in 4.0

View File

@ -585,20 +585,20 @@ class FormsTestCase(SimpleTestCase):
language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=RadioSelect)
f = FrameworkForm(auto_id=False)
self.assertHTMLEqual(str(f['language']), """<ul>
<li><label><input type="radio" name="language" value="P" required> Python</label></li>
<li><label><input type="radio" name="language" value="J" required> Java</label></li>
</ul>""")
self.assertHTMLEqual(str(f['language']), """<div>
<div><label><input type="radio" name="language" value="P" required> Python</label></div>
<div><label><input type="radio" name="language" value="J" required> Java</label></div>
</div>""")
self.assertHTMLEqual(f.as_table(), """<tr><th>Name:</th><td><input type="text" name="name" required></td></tr>
<tr><th>Language:</th><td><ul>
<li><label><input type="radio" name="language" value="P" required> Python</label></li>
<li><label><input type="radio" name="language" value="J" required> Java</label></li>
</ul></td></tr>""")
<tr><th>Language:</th><td><div>
<div><label><input type="radio" name="language" value="P" required> Python</label></div>
<div><label><input type="radio" name="language" value="J" required> Java</label></div>
</div></td></tr>""")
self.assertHTMLEqual(f.as_ul(), """<li>Name: <input type="text" name="name" required></li>
<li>Language: <ul>
<li><label><input type="radio" name="language" value="P" required> Python</label></li>
<li><label><input type="radio" name="language" value="J" required> Java</label></li>
</ul></li>""")
<li>Language: <div>
<div><label><input type="radio" name="language" value="P" required> Python</label></div>
<div><label><input type="radio" name="language" value="J" required> Java</label></div>
</div></li>""")
# Regarding auto_id and <label>, RadioSelect is a special case. Each radio button
# gets a distinct ID, formed by appending an underscore plus the button's
@ -606,12 +606,12 @@ class FormsTestCase(SimpleTestCase):
f = FrameworkForm(auto_id='id_%s')
self.assertHTMLEqual(
str(f['language']),
"""<ul id="id_language">
<li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required>
Python</label></li>
<li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required>
Java</label></li>
</ul>"""
"""<div id="id_language">
<div><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required>
Python</label></div>
<div><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required>
Java</label></div>
</div>"""
)
# When RadioSelect is used with auto_id, and the whole form is printed
@ -621,32 +621,32 @@ Java</label></li>
self.assertHTMLEqual(
f.as_table(),
"""<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" id="id_name" required></td></tr>
<tr><th><label>Language:</label></th><td><ul id="id_language">
<li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required>
Python</label></li>
<li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required>
Java</label></li>
</ul></td></tr>"""
<tr><th><label>Language:</label></th><td><div id="id_language">
<div><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required>
Python</label></div>
<div><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required>
Java</label></div>
</div></td></tr>"""
)
self.assertHTMLEqual(
f.as_ul(),
"""<li><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" required></li>
<li><label>Language:</label> <ul id="id_language">
<li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required>
Python</label></li>
<li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required>
Java</label></li>
</ul></li>"""
<li><label>Language:</label> <div id="id_language">
<div><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required>
Python</label></div>
<div><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required>
Java</label></div>
</div></li>"""
)
self.assertHTMLEqual(
f.as_p(),
"""<p><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" required></p>
<p><label>Language:</label> <ul id="id_language">
<li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required>
Python</label></li>
<li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required>
Java</label></li>
</ul></p>"""
<p><label>Language:</label> <div id="id_language">
<div><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required>
Python</label></div>
<div><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required>
Java</label></div>
</div></p>"""
)
# Test iterating on individual radios in a template
@ -870,20 +870,20 @@ Java</label></li>
)
f = SongForm(auto_id=False)
self.assertHTMLEqual(str(f['composers']), """<ul>
<li><label><input type="checkbox" name="composers" value="J"> John Lennon</label></li>
<li><label><input type="checkbox" name="composers" value="P"> Paul McCartney</label></li>
</ul>""")
self.assertHTMLEqual(str(f['composers']), """<div>
<div><label><input type="checkbox" name="composers" value="J"> John Lennon</label></div>
<div><label><input type="checkbox" name="composers" value="P"> Paul McCartney</label></div>
</div>""")
f = SongForm({'composers': ['J']}, auto_id=False)
self.assertHTMLEqual(str(f['composers']), """<ul>
<li><label><input checked type="checkbox" name="composers" value="J"> John Lennon</label></li>
<li><label><input type="checkbox" name="composers" value="P"> Paul McCartney</label></li>
</ul>""")
self.assertHTMLEqual(str(f['composers']), """<div>
<div><label><input checked type="checkbox" name="composers" value="J"> John Lennon</label></div>
<div><label><input type="checkbox" name="composers" value="P"> Paul McCartney</label></div>
</div>""")
f = SongForm({'composers': ['J', 'P']}, auto_id=False)
self.assertHTMLEqual(str(f['composers']), """<ul>
<li><label><input checked type="checkbox" name="composers" value="J"> John Lennon</label></li>
<li><label><input checked type="checkbox" name="composers" value="P"> Paul McCartney</label></li>
</ul>""")
self.assertHTMLEqual(str(f['composers']), """<div>
<div><label><input checked type="checkbox" name="composers" value="J"> John Lennon</label></div>
<div><label><input checked type="checkbox" name="composers" value="P"> Paul McCartney</label></div>
</div>""")
# Test iterating on individual checkboxes in a template
t = Template('{% for checkbox in form.composers %}<div class="mycheckbox">{{ checkbox }}</div>{% endfor %}')
self.assertHTMLEqual(t.render(Context({'form': f})), """<div class="mycheckbox"><label>
@ -905,12 +905,12 @@ Java</label></li>
f = SongForm(auto_id='%s_id')
self.assertHTMLEqual(
str(f['composers']),
"""<ul id="composers_id">
<li><label for="composers_id_0">
<input type="checkbox" name="composers" value="J" id="composers_id_0"> John Lennon</label></li>
<li><label for="composers_id_1">
<input type="checkbox" name="composers" value="P" id="composers_id_1"> Paul McCartney</label></li>
</ul>"""
"""<div id="composers_id">
<div><label for="composers_id_0">
<input type="checkbox" name="composers" value="J" id="composers_id_0"> John Lennon</label></div>
<div><label for="composers_id_1">
<input type="checkbox" name="composers" value="P" id="composers_id_1"> Paul McCartney</label></div>
</div>"""
)
def test_multiple_choice_list_data(self):

View File

@ -57,15 +57,15 @@ class FormsI18nTests(SimpleTestCase):
self.assertHTMLEqual(
f.as_p(),
'<p><label>\xc5\xf8\xdf:</label>'
'<ul id="id_somechoice">\n'
'<li><label for="id_somechoice_0">'
'<div id="id_somechoice">\n'
'<div><label for="id_somechoice_0">'
'<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" required> '
'En tied\xe4</label></li>\n'
'<li><label for="id_somechoice_1">'
'En tied\xe4</label></div>\n'
'<div><label for="id_somechoice_1">'
'<input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" required> '
'Mies</label></li>\n<li><label for="id_somechoice_2">'
'Mies</label></div>\n<div><label for="id_somechoice_2">'
'<input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" required> '
'Nainen</label></li>\n</ul></p>'
'Nainen</label></div>\n</div></p>'
)
# Translated error messages
@ -77,14 +77,14 @@ class FormsI18nTests(SimpleTestCase):
'\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c'
'\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n'
'<p><label>\xc5\xf8\xdf:</label>'
' <ul id="id_somechoice">\n<li><label for="id_somechoice_0">'
' <div id="id_somechoice">\n<div><label for="id_somechoice_0">'
'<input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" required> '
'En tied\xe4</label></li>\n'
'<li><label for="id_somechoice_1">'
'En tied\xe4</label></div>\n'
'<div><label for="id_somechoice_1">'
'<input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" required> '
'Mies</label></li>\n<li><label for="id_somechoice_2">'
'Mies</label></div>\n<div><label for="id_somechoice_2">'
'<input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" required> '
'Nainen</label></li>\n</ul></p>'
'Nainen</label></div>\n</div></p>'
)
def test_select_translated_text(self):

View File

@ -11,39 +11,39 @@ class CheckboxSelectMultipleTest(WidgetTest):
widget = CheckboxSelectMultiple
def test_render_value(self):
self.check_html(self.widget(choices=self.beatles), 'beatles', ['J'], html=(
"""<ul>
<li><label><input checked type="checkbox" name="beatles" value="J"> John</label></li>
<li><label><input type="checkbox" name="beatles" value="P"> Paul</label></li>
<li><label><input type="checkbox" name="beatles" value="G"> George</label></li>
<li><label><input type="checkbox" name="beatles" value="R"> Ringo</label></li>
</ul>"""
))
self.check_html(self.widget(choices=self.beatles), 'beatles', ['J'], html="""
<div>
<div><label><input checked type="checkbox" name="beatles" value="J"> John</label></div>
<div><label><input type="checkbox" name="beatles" value="P"> Paul</label></div>
<div><label><input type="checkbox" name="beatles" value="G"> George</label></div>
<div><label><input type="checkbox" name="beatles" value="R"> Ringo</label></div>
</div>
""")
def test_render_value_multiple(self):
self.check_html(self.widget(choices=self.beatles), 'beatles', ['J', 'P'], html=(
"""<ul>
<li><label><input checked type="checkbox" name="beatles" value="J"> John</label></li>
<li><label><input checked type="checkbox" name="beatles" value="P"> Paul</label></li>
<li><label><input type="checkbox" name="beatles" value="G"> George</label></li>
<li><label><input type="checkbox" name="beatles" value="R"> Ringo</label></li>
</ul>"""
))
self.check_html(self.widget(choices=self.beatles), 'beatles', ['J', 'P'], html="""
<div>
<div><label><input checked type="checkbox" name="beatles" value="J"> John</label></div>
<div><label><input checked type="checkbox" name="beatles" value="P"> Paul</label></div>
<div><label><input type="checkbox" name="beatles" value="G"> George</label></div>
<div><label><input type="checkbox" name="beatles" value="R"> Ringo</label></div>
</div>
""")
def test_render_none(self):
"""
If the value is None, none of the options are selected, even if the
choices have an empty option.
"""
self.check_html(self.widget(choices=(('', 'Unknown'),) + self.beatles), 'beatles', None, html=(
"""<ul>
<li><label><input type="checkbox" name="beatles" value=""> Unknown</label></li>
<li><label><input type="checkbox" name="beatles" value="J"> John</label></li>
<li><label><input type="checkbox" name="beatles" value="P"> Paul</label></li>
<li><label><input type="checkbox" name="beatles" value="G"> George</label></li>
<li><label><input type="checkbox" name="beatles" value="R"> Ringo</label></li>
</ul>"""
))
self.check_html(self.widget(choices=(('', 'Unknown'),) + self.beatles), 'beatles', None, html="""
<div>
<div><label><input type="checkbox" name="beatles" value=""> Unknown</label></div>
<div><label><input type="checkbox" name="beatles" value="J"> John</label></div>
<div><label><input type="checkbox" name="beatles" value="P"> Paul</label></div>
<div><label><input type="checkbox" name="beatles" value="G"> George</label></div>
<div><label><input type="checkbox" name="beatles" value="R"> Ringo</label></div>
</div>
""")
def test_nested_choices(self):
nested_choices = (
@ -52,31 +52,23 @@ class CheckboxSelectMultipleTest(WidgetTest):
('Video', (('vhs', 'VHS'), ('dvd', 'DVD'))),
)
html = """
<ul id="media">
<li>
<label for="media_0"><input id="media_0" name="nestchoice" type="checkbox" value="unknown"> Unknown</label>
</li>
<li>Audio<ul id="media_1">
<li>
<label for="media_1_0">
<input checked id="media_1_0" name="nestchoice" type="checkbox" value="vinyl"> Vinyl
</label>
</li>
<li>
<label for="media_1_1"><input id="media_1_1" name="nestchoice" type="checkbox" value="cd"> CD</label>
</li>
</ul></li>
<li>Video<ul id="media_2">
<li>
<label for="media_2_0"><input id="media_2_0" name="nestchoice" type="checkbox" value="vhs"> VHS</label>
</li>
<li>
<label for="media_2_1">
<input checked id="media_2_1" name="nestchoice" type="checkbox" value="dvd"> DVD
</label>
</li>
</ul></li>
</ul>
<div id="media">
<div> <label for="media_0">
<input type="checkbox" name="nestchoice" value="unknown" id="media_0"> Unknown</label></div>
<div>
<label>Audio</label>
<div> <label for="media_1_0">
<input checked type="checkbox" name="nestchoice" value="vinyl" id="media_1_0"> Vinyl</label></div>
<div> <label for="media_1_1">
<input type="checkbox" name="nestchoice" value="cd" id="media_1_1"> CD</label></div>
</div><div>
<label>Video</label>
<div> <label for="media_2_0">
<input type="checkbox" name="nestchoice" value="vhs" id="media_2_0"> VHS</label></div>
<div> <label for="media_2_1">
<input type="checkbox" name="nestchoice" value="dvd" id="media_2_1" checked> DVD</label></div>
</div>
</div>
"""
self.check_html(
self.widget(choices=nested_choices), 'nestchoice', ('vinyl', 'dvd'),
@ -90,31 +82,18 @@ class CheckboxSelectMultipleTest(WidgetTest):
('Video', (('vhs', 'VHS'), ('dvd', 'DVD'))),
)
html = """
<ul>
<li>
<label><input name="nestchoice" type="checkbox" value="unknown"> Unknown</label>
</li>
<li>Audio<ul>
<li>
<label>
<input checked name="nestchoice" type="checkbox" value="vinyl"> Vinyl
</label>
</li>
<li>
<label><input name="nestchoice" type="checkbox" value="cd"> CD</label>
</li>
</ul></li>
<li>Video<ul>
<li>
<label><input name="nestchoice" type="checkbox" value="vhs"> VHS</label>
</li>
<li>
<label>
<input checked name="nestchoice" type="checkbox" value="dvd"> DVD
</label>
</li>
</ul></li>
</ul>
<div>
<div> <label><input type="checkbox" name="nestchoice" value="unknown"> Unknown</label></div>
<div>
<label>Audio</label>
<div> <label><input checked type="checkbox" name="nestchoice" value="vinyl"> Vinyl</label></div>
<div> <label><input type="checkbox" name="nestchoice" value="cd"> CD</label></div>
</div><div>
<label>Video</label>
<div> <label><input type="checkbox" name="nestchoice" value="vhs"> VHS</label></div>
<div> <label><input type="checkbox" name="nestchoice" value="dvd"checked> DVD</label></div>
</div>
</div>
"""
self.check_html(self.widget(choices=nested_choices), 'nestchoice', ('vinyl', 'dvd'), html=html)
@ -124,15 +103,15 @@ class CheckboxSelectMultipleTest(WidgetTest):
"""
choices = [('a', 'A'), ('b', 'B'), ('c', 'C')]
html = """
<ul id="abc">
<li>
<div id="abc">
<div>
<label for="abc_0"><input checked type="checkbox" name="letters" value="a" id="abc_0"> A</label>
</li>
<li><label for="abc_1"><input type="checkbox" name="letters" value="b" id="abc_1"> B</label></li>
<li>
</div>
<div><label for="abc_1"><input type="checkbox" name="letters" value="b" id="abc_1"> B</label></div>
<div>
<label for="abc_2"><input checked type="checkbox" name="letters" value="c" id="abc_2"> C</label>
</li>
</ul>
</div>
</div>
"""
self.check_html(self.widget(choices=choices), 'letters', ['a', 'c'], attrs={'id': 'abc'}, html=html)
@ -142,15 +121,15 @@ class CheckboxSelectMultipleTest(WidgetTest):
"""
widget = CheckboxSelectMultiple(attrs={'id': 'abc'}, choices=[('a', 'A'), ('b', 'B'), ('c', 'C')])
html = """
<ul id="abc">
<li>
<div id="abc">
<div>
<label for="abc_0"><input checked type="checkbox" name="letters" value="a" id="abc_0"> A</label>
</li>
<li><label for="abc_1"><input type="checkbox" name="letters" value="b" id="abc_1"> B</label></li>
<li>
</div>
<div><label for="abc_1"><input type="checkbox" name="letters" value="b" id="abc_1"> B</label></div>
<div>
<label for="abc_2"><input checked type="checkbox" name="letters" value="c" id="abc_2"> C</label>
</li>
</ul>
</div>
</div>
"""
self.check_html(widget, 'letters', ['a', 'c'], html=html)
@ -162,11 +141,11 @@ class CheckboxSelectMultipleTest(WidgetTest):
(1000000, 'One million'),
]
html = """
<ul>
<li><label><input type="checkbox" name="numbers" value="1"> One</label></li>
<li><label><input type="checkbox" name="numbers" value="1000"> One thousand</label></li>
<li><label><input type="checkbox" name="numbers" value="1000000"> One million</label></li>
</ul>
<div>
<div><label><input type="checkbox" name="numbers" value="1"> One</label></div>
<div><label><input type="checkbox" name="numbers" value="1000"> One thousand</label></div>
<div><label><input type="checkbox" name="numbers" value="1000000"> One million</label></div>
</div>
"""
self.check_html(self.widget(choices=choices), 'numbers', None, html=html)
@ -175,10 +154,10 @@ class CheckboxSelectMultipleTest(WidgetTest):
(datetime.time(12, 0), 'noon'),
]
html = """
<ul>
<li><label><input type="checkbox" name="times" value="00:00:00"> midnight</label></li>
<li><label><input type="checkbox" name="times" value="12:00:00"> noon</label></li>
</ul>
<div>
<div><label><input type="checkbox" name="times" value="00:00:00"> midnight</label></div>
<div><label><input type="checkbox" name="times" value="12:00:00"> noon</label></div>
</div>
"""
self.check_html(self.widget(choices=choices), 'times', None, html=html)

View File

@ -11,15 +11,15 @@ class RadioSelectTest(WidgetTest):
def test_render(self):
choices = (('', '------'),) + self.beatles
self.check_html(self.widget(choices=choices), 'beatle', 'J', html=(
"""<ul>
<li><label><input type="radio" name="beatle" value=""> ------</label></li>
<li><label><input checked type="radio" name="beatle" value="J"> John</label></li>
<li><label><input type="radio" name="beatle" value="P"> Paul</label></li>
<li><label><input type="radio" name="beatle" value="G"> George</label></li>
<li><label><input type="radio" name="beatle" value="R"> Ringo</label></li>
</ul>"""
))
self.check_html(self.widget(choices=choices), 'beatle', 'J', html="""
<div>
<div><label><input type="radio" name="beatle" value=""> ------</label></div>
<div><label><input checked type="radio" name="beatle" value="J"> John</label></div>
<div><label><input type="radio" name="beatle" value="P"> Paul</label></div>
<div><label><input type="radio" name="beatle" value="G"> George</label></div>
<div><label><input type="radio" name="beatle" value="R"> Ringo</label></div>
</div>
""")
def test_nested_choices(self):
nested_choices = (
@ -28,25 +28,23 @@ class RadioSelectTest(WidgetTest):
('Video', (('vhs', 'VHS'), ('dvd', 'DVD'))),
)
html = """
<ul id="media">
<li>
<label for="media_0"><input id="media_0" name="nestchoice" type="radio" value="unknown"> Unknown</label>
</li>
<li>Audio<ul id="media_1">
<li>
<label for="media_1_0"><input id="media_1_0" name="nestchoice" type="radio" value="vinyl"> Vinyl</label>
</li>
<li><label for="media_1_1"><input id="media_1_1" name="nestchoice" type="radio" value="cd"> CD</label></li>
</ul></li>
<li>Video<ul id="media_2">
<li><label for="media_2_0"><input id="media_2_0" name="nestchoice" type="radio" value="vhs"> VHS</label></li>
<li>
<label for="media_2_1">
<input checked id="media_2_1" name="nestchoice" type="radio" value="dvd"> DVD
</label>
</li>
</ul></li>
</ul>
<div id="media">
<div>
<label for="media_0"><input type="radio" name="nestchoice" value="unknown" id="media_0"> Unknown</label></div>
<div>
<label>Audio</label>
<div>
<label for="media_1_0"><input type="radio" name="nestchoice" value="vinyl" id="media_1_0"> Vinyl</label></div>
<div> <label for="media_1_1"><input type="radio" name="nestchoice" value="cd" id="media_1_1"> CD</label></div>
</div><div>
<label>Video</label>
<div>
<label for="media_2_0"><input type="radio" name="nestchoice" value="vhs" id="media_2_0"> VHS</label></div>
<div>
<label for="media_2_1"><input type="radio" name="nestchoice" value="dvd" id="media_2_1" checked> DVD</label>
</div>
</div>
</div>
"""
self.check_html(
self.widget(choices=nested_choices), 'nestchoice', 'dvd',
@ -60,14 +58,14 @@ class RadioSelectTest(WidgetTest):
"""
widget = RadioSelect(attrs={'id': 'foo'}, choices=self.beatles)
html = """
<ul id="foo">
<li>
<div id="foo">
<div>
<label for="foo_0"><input checked type="radio" id="foo_0" value="J" name="beatle"> John</label>
</li>
<li><label for="foo_1"><input type="radio" id="foo_1" value="P" name="beatle"> Paul</label></li>
<li><label for="foo_2"><input type="radio" id="foo_2" value="G" name="beatle"> George</label></li>
<li><label for="foo_3"><input type="radio" id="foo_3" value="R" name="beatle"> Ringo</label></li>
</ul>
</div>
<div><label for="foo_1"><input type="radio" id="foo_1" value="P" name="beatle"> Paul</label></div>
<div><label for="foo_2"><input type="radio" id="foo_2" value="G" name="beatle"> George</label></div>
<div><label for="foo_3"><input type="radio" id="foo_3" value="R" name="beatle"> Ringo</label></div>
</div>
"""
self.check_html(widget, 'beatle', 'J', html=html)
@ -77,29 +75,29 @@ class RadioSelectTest(WidgetTest):
inputs.
"""
html = """
<ul id="bar">
<li>
<div id="bar">
<div>
<label for="bar_0"><input checked type="radio" id="bar_0" value="J" name="beatle"> John</label>
</li>
<li><label for="bar_1"><input type="radio" id="bar_1" value="P" name="beatle"> Paul</label></li>
<li><label for="bar_2"><input type="radio" id="bar_2" value="G" name="beatle"> George</label></li>
<li><label for="bar_3"><input type="radio" id="bar_3" value="R" name="beatle"> Ringo</label></li>
</ul>
</div>
<div><label for="bar_1"><input type="radio" id="bar_1" value="P" name="beatle"> Paul</label></div>
<div><label for="bar_2"><input type="radio" id="bar_2" value="G" name="beatle"> George</label></div>
<div><label for="bar_3"><input type="radio" id="bar_3" value="R" name="beatle"> Ringo</label></div>
</div>
"""
self.check_html(self.widget(choices=self.beatles), 'beatle', 'J', attrs={'id': 'bar'}, html=html)
def test_class_attrs(self):
"""
The <ul> in the multiple_input.html widget template include the class
The <div> in the multiple_input.html widget template include the class
attribute.
"""
html = """
<ul class="bar">
<li><label><input checked type="radio" class="bar" value="J" name="beatle"> John</label></li>
<li><label><input type="radio" class="bar" value="P" name="beatle"> Paul</label></li>
<li><label><input type="radio" class="bar" value="G" name="beatle"> George</label></li>
<li><label><input type="radio" class="bar" value="R" name="beatle"> Ringo</label></li>
</ul>
<div class="bar">
<div><label><input checked type="radio" class="bar" value="J" name="beatle"> John</label></div>
<div><label><input type="radio" class="bar" value="P" name="beatle"> Paul</label></div>
<div><label><input type="radio" class="bar" value="G" name="beatle"> George</label></div>
<div><label><input type="radio" class="bar" value="R" name="beatle"> Ringo</label></div>
</div>
"""
self.check_html(self.widget(choices=self.beatles), 'beatle', 'J', attrs={'class': 'bar'}, html=html)
@ -111,11 +109,11 @@ class RadioSelectTest(WidgetTest):
(1000000, 'One million'),
]
html = """
<ul>
<li><label><input type="radio" name="number" value="1"> One</label></li>
<li><label><input type="radio" name="number" value="1000"> One thousand</label></li>
<li><label><input type="radio" name="number" value="1000000"> One million</label></li>
</ul>
<div>
<div><label><input type="radio" name="number" value="1"> One</label></div>
<div><label><input type="radio" name="number" value="1000"> One thousand</label></div>
<div><label><input type="radio" name="number" value="1000000"> One million</label></div>
</div>
"""
self.check_html(self.widget(choices=choices), 'number', None, html=html)
@ -124,22 +122,22 @@ class RadioSelectTest(WidgetTest):
(datetime.time(12, 0), 'noon'),
]
html = """
<ul>
<li><label><input type="radio" name="time" value="00:00:00"> midnight</label></li>
<li><label><input type="radio" name="time" value="12:00:00"> noon</label></li>
</ul>
<div>
<div><label><input type="radio" name="time" value="00:00:00"> midnight</label></div>
<div><label><input type="radio" name="time" value="12:00:00"> noon</label></div>
</div>
"""
self.check_html(self.widget(choices=choices), 'time', None, html=html)
def test_render_as_subwidget(self):
"""A RadioSelect as a subwidget of MultiWidget."""
choices = (('', '------'),) + self.beatles
self.check_html(MultiWidget([self.widget(choices=choices)]), 'beatle', ['J'], html=(
"""<ul>
<li><label><input type="radio" name="beatle_0" value=""> ------</label></li>
<li><label><input checked type="radio" name="beatle_0" value="J"> John</label></li>
<li><label><input type="radio" name="beatle_0" value="P"> Paul</label></li>
<li><label><input type="radio" name="beatle_0" value="G"> George</label></li>
<li><label><input type="radio" name="beatle_0" value="R"> Ringo</label></li>
</ul>"""
))
self.check_html(MultiWidget([self.widget(choices=choices)]), 'beatle', ['J'], html="""
<div>
<div><label><input type="radio" name="beatle_0" value=""> ------</label></div>
<div><label><input checked type="radio" name="beatle_0" value="J"> John</label></div>
<div><label><input type="radio" name="beatle_0" value="P"> Paul</label></div>
<div><label><input type="radio" name="beatle_0" value="G"> George</label></div>
<div><label><input type="radio" name="beatle_0" value="R"> Ringo</label></div>
</div>
""")

View File

@ -294,14 +294,14 @@ class ModelChoiceFieldTests(TestCase):
field = CustomModelMultipleChoiceField(Category.objects.all())
self.assertHTMLEqual(
field.widget.render('name', []), (
'<ul>'
'<li><label><input type="checkbox" name="name" value="%d" '
'data-slug="entertainment">Entertainment</label></li>'
'<li><label><input type="checkbox" name="name" value="%d" '
'data-slug="test">A test</label></li>'
'<li><label><input type="checkbox" name="name" value="%d" '
'data-slug="third-test">Third</label></li>'
'</ul>'
'<div>'
'<div><label><input type="checkbox" name="name" value="%d" '
'data-slug="entertainment">Entertainment</label></div>'
'<div><label><input type="checkbox" name="name" value="%d" '
'data-slug="test">A test</label></div>'
'<div><label><input type="checkbox" name="name" value="%d" '
'data-slug="third-test">Third</label></div>'
'</div>'
) % (self.c1.pk, self.c2.pk, self.c3.pk),
)
@ -334,11 +334,11 @@ class ModelChoiceFieldTests(TestCase):
field = CustomModelMultipleChoiceField(Category.objects.all())
self.assertHTMLEqual(
field.widget.render('name', []),
'''<ul>
<li><label><input type="checkbox" name="name" value="%d" data-slug="entertainment">Entertainment</label></li>
<li><label><input type="checkbox" name="name" value="%d" data-slug="test">A test</label></li>
<li><label><input type="checkbox" name="name" value="%d" data-slug="third-test">Third</label></li>
</ul>''' % (self.c1.pk, self.c2.pk, self.c3.pk),
"""<div>
<div><label><input type="checkbox" name="name" value="%d" data-slug="entertainment">Entertainment</label></div>
<div><label><input type="checkbox" name="name" value="%d" data-slug="test">A test</label></div>
<div><label><input type="checkbox" name="name" value="%d" data-slug="third-test">Third</label></div>
</div>""" % (self.c1.pk, self.c2.pk, self.c3.pk),
)
def test_choices_not_fetched_when_not_rendering(self):