diff --git a/django/forms/widgets.py b/django/forms/widgets.py
index 41263b0905..b0e355eeb6 100644
--- a/django/forms/widgets.py
+++ b/django/forms/widgets.py
@@ -646,10 +646,13 @@ class RadioFieldRenderer(object):
def render(self):
"""Outputs a
for this set of radio fields."""
- return format_html('
\n{0}\n
',
- format_html_join('\n', '
{0}
',
- [(force_text(w),) for w in self]
- ))
+ id_ = self.attrs.get('id', None)
+ start_tag = format_html('
', id_) if id_ else '
'
+ output = [start_tag]
+ for widget in self:
+ output.append(format_html('
{0}
', force_text(widget)))
+ output.append('
')
+ return mark_safe('\n'.join(output))
class RadioSelect(Select):
renderer = RadioFieldRenderer
diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt
index 45d9e8a4dc..836389125a 100644
--- a/docs/ref/forms/widgets.txt
+++ b/docs/ref/forms/widgets.txt
@@ -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 ``
`` container will now receive the ``id`` attribute defined on
+the widget.
+
``CheckboxSelectMultiple``
~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/forms_tests/tests/test_forms.py b/tests/forms_tests/tests/test_forms.py
index 49a93b2ad0..45e62a492c 100644
--- a/tests/forms_tests/tests/test_forms.py
+++ b/tests/forms_tests/tests/test_forms.py
@@ -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']), """
+ self.assertHTMLEqual(str(f['language']), """
""")
@@ -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(), """
-
+
""")
self.assertHTMLEqual(f.as_ul(), """
-
+
""")
self.assertHTMLEqual(f.as_p(), """
-
+
""")
diff --git a/tests/forms_tests/tests/test_regressions.py b/tests/forms_tests/tests/test_regressions.py
index ba741bc16b..be9dc8c593 100644
--- a/tests/forms_tests/tests/test_regressions.py
+++ b/tests/forms_tests/tests/test_regressions.py
@@ -54,7 +54,7 @@ class FormsRegressionsTestCase(TestCase):
somechoice = ChoiceField(choices=GENDERS, widget=RadioSelect(), label='\xc5\xf8\xdf')
f = SomeForm()
- self.assertHTMLEqual(f.as_p(), '
\n\n\n\n
')
+ self.assertHTMLEqual(f.as_p(), '
\n\n\n\n
')
# Testing choice validation with UTF-8 bytestrings as input (these are the
# Russian abbreviations "мес." and "шт.".
@@ -70,7 +70,7 @@ class FormsRegressionsTestCase(TestCase):
# Translated error messages used to be buggy.
with override('ru'):
f = SomeForm({})
- self.assertHTMLEqual(f.as_p(), '