diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 91d9e9072..e4a7ddfa5 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -328,9 +328,6 @@ class HTMLFormRenderer(BaseRenderer): style['template_pack'] = parent_style.get('template_pack', self.template_pack) style['renderer'] = self - # Get a clone of the field with text-only value representation. - field = field.as_form_field() - if style.get('input_type') == 'datetime-local' and isinstance(field.value, six.text_type): field.value = field.value.rstrip('Z') diff --git a/rest_framework/templates/rest_framework/horizontal/input.html b/rest_framework/templates/rest_framework/horizontal/input.html index 9e5bbd0f7..c691b801d 100644 --- a/rest_framework/templates/rest_framework/horizontal/input.html +++ b/rest_framework/templates/rest_framework/horizontal/input.html @@ -6,7 +6,7 @@ {% endif %}
- + {% if field.errors %} {% for error in field.errors %} diff --git a/rest_framework/templates/rest_framework/horizontal/select.html b/rest_framework/templates/rest_framework/horizontal/select.html index 3c9e36bbb..48cf273a8 100644 --- a/rest_framework/templates/rest_framework/horizontal/select.html +++ b/rest_framework/templates/rest_framework/horizontal/select.html @@ -8,7 +8,7 @@
+ {% if field.errors %} {% for error in field.errors %} diff --git a/rest_framework/templates/rest_framework/inline/input.html b/rest_framework/templates/rest_framework/inline/input.html index f28e8f11c..c749ae055 100644 --- a/rest_framework/templates/rest_framework/inline/input.html +++ b/rest_framework/templates/rest_framework/inline/input.html @@ -5,5 +5,5 @@ {% endif %} - +
diff --git a/rest_framework/templates/rest_framework/inline/select.html b/rest_framework/templates/rest_framework/inline/select.html index 99f10ae71..f4dae58cd 100644 --- a/rest_framework/templates/rest_framework/inline/select.html +++ b/rest_framework/templates/rest_framework/inline/select.html @@ -7,7 +7,7 @@ +
diff --git a/rest_framework/templates/rest_framework/vertical/input.html b/rest_framework/templates/rest_framework/vertical/input.html index 504dcc28e..f99340eab 100644 --- a/rest_framework/templates/rest_framework/vertical/input.html +++ b/rest_framework/templates/rest_framework/vertical/input.html @@ -3,7 +3,7 @@ {% endif %} - + {% if field.errors %} {% for error in field.errors %} diff --git a/rest_framework/templates/rest_framework/vertical/select.html b/rest_framework/templates/rest_framework/vertical/select.html index 9736fc072..6677382ec 100644 --- a/rest_framework/templates/rest_framework/vertical/select.html +++ b/rest_framework/templates/rest_framework/vertical/select.html @@ -7,7 +7,7 @@ + {% if field.errors %} {% for error in field.errors %}{{ error }}{% endfor %} diff --git a/rest_framework/utils/serializer_helpers.py b/rest_framework/utils/serializer_helpers.py index 115f1e186..d92e17999 100644 --- a/rest_framework/utils/serializer_helpers.py +++ b/rest_framework/utils/serializer_helpers.py @@ -72,15 +72,17 @@ class BoundField(object): def _proxy_class(self): return self._field.__class__ + @property + def string_value(self): + if self.value is None or self.value is False: + return '' + return force_text(self.value) + def __repr__(self): return unicode_to_repr('<%s value=%s errors=%s>' % ( self.__class__.__name__, self.value, self.errors )) - 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) - class NestedBoundField(BoundField): """ @@ -106,15 +108,6 @@ class NestedBoundField(BoundField): return NestedBoundField(field, value, error, prefix=self.name + '.') return BoundField(field, value, error, prefix=self.name + '.') - def as_form_field(self): - values = {} - for key, value in self.value.items(): - if isinstance(value, (list, dict)): - 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) - class BindingDict(collections.MutableMapping): """ diff --git a/tests/test_bound_fields.py b/tests/test_bound_fields.py index f2fac8f0d..4aff741ce 100644 --- a/tests/test_bound_fields.py +++ b/tests/test_bound_fields.py @@ -45,15 +45,15 @@ class TestSimpleBoundField: assert serializer['amount'].errors is None assert serializer['amount'].name == 'amount' - def test_as_form_fields(self): + def test_string_value(self): class ExampleSerializer(serializers.Serializer): bool_field = serializers.BooleanField() null_field = serializers.IntegerField(allow_null=True) serializer = ExampleSerializer(data={'bool_field': False, 'null_field': None}) assert serializer.is_valid() - assert serializer['bool_field'].as_form_field().value == '' - assert serializer['null_field'].as_form_field().value == '' + assert serializer['bool_field'].string_value == '' + assert serializer['null_field'].string_value == '' class TestNestedBoundField: @@ -78,7 +78,7 @@ class TestNestedBoundField: assert serializer['nested']['amount'].errors is None assert serializer['nested']['amount'].name == 'nested.amount' - def test_as_form_fields(self): + def test_string_value(self): class Nested(serializers.Serializer): bool_field = serializers.BooleanField() null_field = serializers.IntegerField(allow_null=True) @@ -88,8 +88,8 @@ class TestNestedBoundField: serializer = ExampleSerializer(data={'nested': {'bool_field': False, 'null_field': None}}) assert serializer.is_valid() - assert serializer['nested']['bool_field'].as_form_field().value == '' - assert serializer['nested']['null_field'].as_form_field().value == '' + assert serializer['nested']['bool_field'].string_value == '' + assert serializer['nested']['null_field'].string_value == '' def test_rendering_nested_fields_with_none_value(self): from rest_framework.renderers import HTMLFormRenderer diff --git a/tests/test_renderers.py b/tests/test_renderers.py index a947f8b7d..053cbe3d2 100644 --- a/tests/test_renderers.py +++ b/tests/test_renderers.py @@ -481,3 +481,147 @@ 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) + + +class TestIntegerFieldHTMLFormRenderer(TestCase): + """ + Test rendering IntegerField with HTMLFormRenderer. + """ + + def setUp(self): + class TestSerializer(serializers.Serializer): + test_field = serializers.IntegerField() + + self.TestSerializer = TestSerializer + self.renderer = HTMLFormRenderer() + + def test_render_zero(self): + serializer = self.TestSerializer(data={'test_field': '0'}) + serializer.is_valid() + + result = self.renderer.render(serializer.data) + + self.assertIsInstance(result, SafeText) + + self.assertIsNotNone(re.search(r'