Loading django/forms/widgets.py +7 −4 Original line number Diff line number Diff line Loading @@ -646,10 +646,13 @@ class RadioFieldRenderer(object): def render(self): """Outputs a <ul> for this set of radio fields.""" return format_html('<ul>\n{0}\n</ul>', format_html_join('\n', '<li>{0}</li>', [(force_text(w),) for w in self] )) id_ = self.attrs.get('id', None) start_tag = format_html('<ul id="{0}">', id_) if id_ else '<ul>' output = [start_tag] for widget in self: output.append(format_html('<li>{0}</li>', force_text(widget))) output.append('</ul>') return mark_safe('\n'.join(output)) class RadioSelect(Select): renderer = RadioFieldRenderer Loading docs/ref/forms/widgets.txt +5 −0 Original line number Diff line number Diff line Loading @@ -633,6 +633,11 @@ Selector and checkbox widgets If you decide not to loop over the radio buttons -- e.g., if your template simply includes ``{{ myform.beatles }}`` -- they'll be output in a ``<ul>`` with ``<li>`` tags, as above. .. versionchanged:: 1.6 The outer ``<ul>`` container will now receive the ``id`` attribute defined on the widget. ``CheckboxSelectMultiple`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading tests/forms_tests/tests/test_forms.py +4 −4 Original line number Diff line number Diff line Loading @@ -407,7 +407,7 @@ class FormsTestCase(TestCase): # gets a distinct ID, formed by appending an underscore plus the button's # zero-based index. f = FrameworkForm(auto_id='id_%s') self.assertHTMLEqual(str(f['language']), """<ul> 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" /> Python</label></li> <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> </ul>""") Loading @@ -416,17 +416,17 @@ class FormsTestCase(TestCase): # either as_table() or as_ul(), the label for the RadioSelect will point to the # ID of the *first* radio button. self.assertHTMLEqual(f.as_table(), """<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" id="id_name" /></td></tr> <tr><th><label for="id_language_0">Language:</label></th><td><ul> <tr><th><label for="id_language_0">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" /> Python</label></li> <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> </ul></td></tr>""") self.assertHTMLEqual(f.as_ul(), """<li><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></li> <li><label for="id_language_0">Language:</label> <ul> <li><label for="id_language_0">Language:</label> <ul id="id_language"> <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> </ul></li>""") self.assertHTMLEqual(f.as_p(), """<p><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></p> <p><label for="id_language_0">Language:</label> <ul> <p><label for="id_language_0">Language:</label> <ul id="id_language"> <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> </ul></p>""") Loading tests/forms_tests/tests/test_regressions.py +2 −2 Original line number Diff line number Diff line Loading @@ -54,7 +54,7 @@ class FormsRegressionsTestCase(TestCase): somechoice = ChoiceField(choices=GENDERS, widget=RadioSelect(), label='\xc5\xf8\xdf') f = SomeForm() self.assertHTMLEqual(f.as_p(), '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul>\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>') self.assertHTMLEqual(f.as_p(), '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul id="id_somechoice">\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>') # Testing choice validation with UTF-8 bytestrings as input (these are the # Russian abbreviations "мес." and "шт.". Loading @@ -70,7 +70,7 @@ class FormsRegressionsTestCase(TestCase): # Translated error messages used to be buggy. with override('ru'): f = SomeForm({}) self.assertHTMLEqual(f.as_p(), '<ul class="errorlist"><li>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul>\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>') self.assertHTMLEqual(f.as_p(), '<ul class="errorlist"><li>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul id="id_somechoice">\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>') # Deep copying translated text shouldn't raise an error) from django.utils.translation import gettext_lazy Loading tests/forms_tests/tests/test_widgets.py +2 −2 Original line number Diff line number Diff line Loading @@ -684,7 +684,7 @@ beatle J R Ringo False""") # Attributes provided at instantiation are passed to the constituent inputs w = RadioSelect(attrs={'id':'foo'}) self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul> self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul id="foo"> <li><label for="foo_0"><input checked="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> Loading @@ -693,7 +693,7 @@ beatle J R Ringo False""") # Attributes provided at render-time are passed to the constituent inputs w = RadioSelect() self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'}), """<ul> self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'}), """<ul id="bar"> <li><label for="bar_0"><input checked="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> Loading Loading
django/forms/widgets.py +7 −4 Original line number Diff line number Diff line Loading @@ -646,10 +646,13 @@ class RadioFieldRenderer(object): def render(self): """Outputs a <ul> for this set of radio fields.""" return format_html('<ul>\n{0}\n</ul>', format_html_join('\n', '<li>{0}</li>', [(force_text(w),) for w in self] )) id_ = self.attrs.get('id', None) start_tag = format_html('<ul id="{0}">', id_) if id_ else '<ul>' output = [start_tag] for widget in self: output.append(format_html('<li>{0}</li>', force_text(widget))) output.append('</ul>') return mark_safe('\n'.join(output)) class RadioSelect(Select): renderer = RadioFieldRenderer Loading
docs/ref/forms/widgets.txt +5 −0 Original line number Diff line number Diff line Loading @@ -633,6 +633,11 @@ Selector and checkbox widgets If you decide not to loop over the radio buttons -- e.g., if your template simply includes ``{{ myform.beatles }}`` -- they'll be output in a ``<ul>`` with ``<li>`` tags, as above. .. versionchanged:: 1.6 The outer ``<ul>`` container will now receive the ``id`` attribute defined on the widget. ``CheckboxSelectMultiple`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ Loading
tests/forms_tests/tests/test_forms.py +4 −4 Original line number Diff line number Diff line Loading @@ -407,7 +407,7 @@ class FormsTestCase(TestCase): # gets a distinct ID, formed by appending an underscore plus the button's # zero-based index. f = FrameworkForm(auto_id='id_%s') self.assertHTMLEqual(str(f['language']), """<ul> 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" /> Python</label></li> <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> </ul>""") Loading @@ -416,17 +416,17 @@ class FormsTestCase(TestCase): # either as_table() or as_ul(), the label for the RadioSelect will point to the # ID of the *first* radio button. self.assertHTMLEqual(f.as_table(), """<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" id="id_name" /></td></tr> <tr><th><label for="id_language_0">Language:</label></th><td><ul> <tr><th><label for="id_language_0">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" /> Python</label></li> <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> </ul></td></tr>""") self.assertHTMLEqual(f.as_ul(), """<li><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></li> <li><label for="id_language_0">Language:</label> <ul> <li><label for="id_language_0">Language:</label> <ul id="id_language"> <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> </ul></li>""") self.assertHTMLEqual(f.as_p(), """<p><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></p> <p><label for="id_language_0">Language:</label> <ul> <p><label for="id_language_0">Language:</label> <ul id="id_language"> <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" /> Python</label></li> <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" /> Java</label></li> </ul></p>""") Loading
tests/forms_tests/tests/test_regressions.py +2 −2 Original line number Diff line number Diff line Loading @@ -54,7 +54,7 @@ class FormsRegressionsTestCase(TestCase): somechoice = ChoiceField(choices=GENDERS, widget=RadioSelect(), label='\xc5\xf8\xdf') f = SomeForm() self.assertHTMLEqual(f.as_p(), '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul>\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>') self.assertHTMLEqual(f.as_p(), '<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul id="id_somechoice">\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>') # Testing choice validation with UTF-8 bytestrings as input (these are the # Russian abbreviations "мес." and "шт.". Loading @@ -70,7 +70,7 @@ class FormsRegressionsTestCase(TestCase): # Translated error messages used to be buggy. with override('ru'): f = SomeForm({}) self.assertHTMLEqual(f.as_p(), '<ul class="errorlist"><li>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul>\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>') self.assertHTMLEqual(f.as_p(), '<ul class="errorlist"><li>\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u0435.</li></ul>\n<p><label for="id_somechoice_0">\xc5\xf8\xdf:</label> <ul id="id_somechoice">\n<li><label for="id_somechoice_0"><input type="radio" id="id_somechoice_0" value="\xc5" name="somechoice" /> En tied\xe4</label></li>\n<li><label for="id_somechoice_1"><input type="radio" id="id_somechoice_1" value="\xf8" name="somechoice" /> Mies</label></li>\n<li><label for="id_somechoice_2"><input type="radio" id="id_somechoice_2" value="\xdf" name="somechoice" /> Nainen</label></li>\n</ul></p>') # Deep copying translated text shouldn't raise an error) from django.utils.translation import gettext_lazy Loading
tests/forms_tests/tests/test_widgets.py +2 −2 Original line number Diff line number Diff line Loading @@ -684,7 +684,7 @@ beatle J R Ringo False""") # Attributes provided at instantiation are passed to the constituent inputs w = RadioSelect(attrs={'id':'foo'}) self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul> self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))), """<ul id="foo"> <li><label for="foo_0"><input checked="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> Loading @@ -693,7 +693,7 @@ beatle J R Ringo False""") # Attributes provided at render-time are passed to the constituent inputs w = RadioSelect() self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'}), """<ul> self.assertHTMLEqual(w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'}), """<ul id="bar"> <li><label for="bar_0"><input checked="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> Loading