diff --git a/django/forms/templates/django/forms/widgets/input.html b/django/forms/templates/django/forms/widgets/input.html
index abbdf6bd26d..5feef43c553 100644
--- a/django/forms/templates/django/forms/widgets/input.html
+++ b/django/forms/templates/django/forms/widgets/input.html
@@ -1 +1 @@
-
+
diff --git a/django/forms/templates/django/forms/widgets/select_option.html b/django/forms/templates/django/forms/widgets/select_option.html
index c6355f69dd5..8d31961dd33 100644
--- a/django/forms/templates/django/forms/widgets/select_option.html
+++ b/django/forms/templates/django/forms/widgets/select_option.html
@@ -1 +1 @@
-
+
diff --git a/django/forms/widgets.py b/django/forms/widgets.py
index 5b47aa691de..282ba0b4818 100644
--- a/django/forms/widgets.py
+++ b/django/forms/widgets.py
@@ -591,7 +591,7 @@ class ChoiceWidget(Widget):
option_attrs['id'] = self.id_for_label(option_attrs['id'], index)
return {
'name': name,
- 'value': str(value),
+ 'value': value,
'label': label,
'selected': selected,
'index': index,
diff --git a/docs/releases/1.11.3.txt b/docs/releases/1.11.3.txt
index 1e2ddddb66d..9aab4fbfb76 100644
--- a/docs/releases/1.11.3.txt
+++ b/docs/releases/1.11.3.txt
@@ -44,3 +44,10 @@ Bugfixes
* Prevented attribute values in the ``django/forms/widgets/attrs.html``
template from being localized so that numeric attributes (e.g. ``max`` and
``min``) of ``NumberInput`` work correctly (:ticket:`28303`).
+
+* Removed casting of the option value to a string in the template context of
+ the ``CheckboxSelectMultiple``, ``NullBooleanSelect``, ``RadioSelect``,
+ ``SelectMultiple``, and ``Select`` widgets (:ticket:`28176`). In Django
+ 1.11.1, casting was added in Python to avoid localization of numeric values
+ in Django templates, but this made some use cases more difficult. Casting is
+ now done in the template using the ``|stringformat:'s'`` filter.
diff --git a/tests/forms_tests/widget_tests/test_select.py b/tests/forms_tests/widget_tests/test_select.py
index a5201e96e88..beba21fe2dc 100644
--- a/tests/forms_tests/widget_tests/test_select.py
+++ b/tests/forms_tests/widget_tests/test_select.py
@@ -348,6 +348,12 @@ class SelectTest(WidgetTest):
)
self.assertEqual(index, 2)
+ def test_optgroups_integer_choices(self):
+ """The option 'value' is the same type as what's in `choices`."""
+ groups = list(self.widget(choices=[[0, 'choice text']]).optgroups('name', ['vhs']))
+ label, options, index = groups[0]
+ self.assertEqual(options[0]['value'], 0)
+
def test_deepcopy(self):
"""
__deepcopy__() should copy all attributes properly (#25085).