mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Refs #32338 -- Made RadioSelect/CheckboxSelectMultiple render in <div> tags.
This improves accessibility for screen reader users.
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							a5cb1ef6eb
						
					
				
				
					commit
					5942ab5eb1
				
			| @@ -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> | ||||
|   | ||||
| @@ -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 %} | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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) | ||||
|  | ||||
|   | ||||
| @@ -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> | ||||
|         """) | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user