diff --git a/rest_framework/templates/rest_framework/horizontal/select.html b/rest_framework/templates/rest_framework/horizontal/select.html
index 3c9e36bbb..216841f06 100644
--- a/rest_framework/templates/rest_framework/horizontal/select.html
+++ b/rest_framework/templates/rest_framework/horizontal/select.html
@@ -16,7 +16,7 @@
{% elif select.end_option_group %}
{% else %}
-
+
{% endif %}
{% endfor %}
diff --git a/rest_framework/templates/rest_framework/horizontal/select_multiple.html b/rest_framework/templates/rest_framework/horizontal/select_multiple.html
index 68b40ecc3..83abe19d5 100644
--- a/rest_framework/templates/rest_framework/horizontal/select_multiple.html
+++ b/rest_framework/templates/rest_framework/horizontal/select_multiple.html
@@ -16,7 +16,7 @@
{% elif select.end_option_group %}
{% else %}
-
+
{% endif %}
{% empty %}
diff --git a/rest_framework/templates/rest_framework/inline/select.html b/rest_framework/templates/rest_framework/inline/select.html
index 99f10ae71..2796dba24 100644
--- a/rest_framework/templates/rest_framework/inline/select.html
+++ b/rest_framework/templates/rest_framework/inline/select.html
@@ -15,7 +15,7 @@
{% elif select.end_option_group %}
{% else %}
-
+
{% endif %}
{% endfor %}
diff --git a/rest_framework/templates/rest_framework/inline/select_multiple.html b/rest_framework/templates/rest_framework/inline/select_multiple.html
index 1c0e96b3c..a9bd08be1 100644
--- a/rest_framework/templates/rest_framework/inline/select_multiple.html
+++ b/rest_framework/templates/rest_framework/inline/select_multiple.html
@@ -15,7 +15,7 @@
{% elif select.end_option_group %}
{% else %}
-
+
{% endif %}
{% empty %}
diff --git a/rest_framework/templates/rest_framework/vertical/select.html b/rest_framework/templates/rest_framework/vertical/select.html
index 9736fc072..e9ea536d8 100644
--- a/rest_framework/templates/rest_framework/vertical/select.html
+++ b/rest_framework/templates/rest_framework/vertical/select.html
@@ -15,7 +15,7 @@
{% elif select.end_option_group %}
{% else %}
-
+
{% endif %}
{% endfor %}
diff --git a/rest_framework/templates/rest_framework/vertical/select_multiple.html b/rest_framework/templates/rest_framework/vertical/select_multiple.html
index 8d0be0427..65872f369 100644
--- a/rest_framework/templates/rest_framework/vertical/select_multiple.html
+++ b/rest_framework/templates/rest_framework/vertical/select_multiple.html
@@ -15,7 +15,7 @@
{% elif select.end_option_group %}
{% else %}
-
+
{% endif %}
{% empty %}
diff --git a/rest_framework/utils/serializer_helpers.py b/rest_framework/utils/serializer_helpers.py
index 115f1e186..cb35416e4 100644
--- a/rest_framework/utils/serializer_helpers.py
+++ b/rest_framework/utils/serializer_helpers.py
@@ -8,6 +8,10 @@ from django.utils.encoding import force_text
from rest_framework.compat import unicode_to_repr
+# A singleton helper value to detect unset keyword arguments
+unset = object()
+
+
class ReturnDict(OrderedDict):
"""
Return object from `serializer.data` for the `Serializer` class.
@@ -58,10 +62,11 @@ class BoundField(object):
providing an API similar to Django forms and form fields.
"""
- def __init__(self, field, value, errors, prefix=''):
+ def __init__(self, field, value, errors, prefix='', basic_value=unset):
self._field = field
self._prefix = prefix
self.value = value
+ self.basic_value = value if basic_value is unset else basic_value
self.errors = errors
self.name = prefix + self.field_name
@@ -79,7 +84,8 @@ class BoundField(object):
def as_form_field(self):
value = '' if (self.value is None or self.value is False) else force_text(self.value)
- return self.__class__(self._field, value, self.errors, self._prefix)
+ return self.__class__(self._field, value, self.errors, self._prefix,
+ self.basic_value)
class NestedBoundField(BoundField):
@@ -89,10 +95,11 @@ class NestedBoundField(BoundField):
`BoundField` that is used for serializer fields.
"""
- def __init__(self, field, value, errors, prefix=''):
+ def __init__(self, field, value, errors, prefix='', basic_value=unset):
if value is None or value is '':
value = {}
- super(NestedBoundField, self).__init__(field, value, errors, prefix)
+ super(NestedBoundField, self).__init__(field, value, errors, prefix,
+ basic_value)
def __iter__(self):
for field in self.fields.values():
@@ -113,7 +120,8 @@ class NestedBoundField(BoundField):
values[key] = value
else:
values[key] = '' if (value is None or value is False) else force_text(value)
- return self.__class__(self._field, values, self.errors, self._prefix)
+ return self.__class__(self._field, values, self.errors, self._prefix,
+ self.basic_value)
class BindingDict(collections.MutableMapping):
diff --git a/tests/test_renderers.py b/tests/test_renderers.py
index a947f8b7d..a2620e93c 100644
--- a/tests/test_renderers.py
+++ b/tests/test_renderers.py
@@ -481,3 +481,90 @@ class TestHTMLFormRenderer(TestCase):
result = renderer.render(self.serializer.data, None, {})
self.assertIsInstance(result, SafeText)
+
+
+class TestChoiceFieldHTMLFormRenderer(TestCase):
+ """
+ Test rendering ChoiceField with HTMLFormRenderer.
+ """
+
+ def setUp(self):
+ choices = ((1, 'Option1'), (2, 'Option2'), (12, 'Option12'))
+
+ class TestSerializer(serializers.Serializer):
+ test_field = serializers.ChoiceField(choices=choices,
+ initial=2)
+
+ self.TestSerializer = TestSerializer
+ self.renderer = HTMLFormRenderer()
+
+ def test_render_initial_option(self):
+ serializer = self.TestSerializer()
+ result = self.renderer.render(serializer.data)
+
+ self.assertIsInstance(result, SafeText)
+
+ self.assertInHTML('',
+ result)
+ self.assertInHTML('', result)
+ self.assertInHTML('', result)
+
+ def test_render_selected_option(self):
+ serializer = self.TestSerializer(data={'test_field': '12'})
+
+ serializer.is_valid()
+ result = self.renderer.render(serializer.data)
+
+ self.assertIsInstance(result, SafeText)
+
+ self.assertInHTML('',
+ result)
+ self.assertInHTML('', result)
+ self.assertInHTML('', result)
+
+
+class TestMultipleChoiceFieldHTMLFormRenderer(TestCase):
+ """
+ Test rendering MultipleChoiceField with HTMLFormRenderer.
+ """
+
+ def setUp(self):
+ self.renderer = HTMLFormRenderer()
+
+ def test_render_selected_option_with_string_option_ids(self):
+ choices = (('1', 'Option1'), ('2', 'Option2'), ('12', 'Option12'),
+ ('}', 'OptionBrace'))
+
+ class TestSerializer(serializers.Serializer):
+ test_field = serializers.MultipleChoiceField(choices=choices)
+
+ serializer = TestSerializer(data={'test_field': ['12']})
+ serializer.is_valid()
+
+ result = self.renderer.render(serializer.data)
+
+ self.assertIsInstance(result, SafeText)
+
+ self.assertInHTML('',
+ result)
+ self.assertInHTML('', result)
+ self.assertInHTML('', result)
+ self.assertInHTML('', result)
+
+ def test_render_selected_option_with_integer_option_ids(self):
+ choices = ((1, 'Option1'), (2, 'Option2'), (12, 'Option12'))
+
+ class TestSerializer(serializers.Serializer):
+ test_field = serializers.MultipleChoiceField(choices=choices)
+
+ serializer = TestSerializer(data={'test_field': ['12']})
+ serializer.is_valid()
+
+ result = self.renderer.render(serializer.data)
+
+ self.assertIsInstance(result, SafeText)
+
+ self.assertInHTML('',
+ result)
+ self.assertInHTML('', result)
+ self.assertInHTML('', result)