mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-08 06:14:47 +03:00
Improve field value handling in HTML form output
Let each form field's HTML template decide if it needs native or string-ified field value, instead of forcing all templates to always work only with unnecessarily restrictive string representation. Fixes #4120, #4121
This commit is contained in:
parent
2cb71571cd
commit
dc0442c186
|
@ -319,9 +319,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')
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{% endif %}
|
||||
|
||||
<div class="col-sm-10">
|
||||
<input name="{{ field.name }}" {% if style.input_type != "file" %}class="form-control"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.value %}value="{{ field.value }}"{% endif %}>
|
||||
<input name="{{ field.name }}" {% if style.input_type != "file" %}class="form-control"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.string_value %}value="{{ field.string_value }}"{% endif %}>
|
||||
|
||||
{% if field.errors %}
|
||||
{% for error in field.errors %}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<div class="col-sm-10">
|
||||
<select class="form-control" name="{{ field.name }}">
|
||||
{% if field.allow_null or field.allow_blank %}
|
||||
<option value="" {% if not field.value %}selected{% endif %}>--------</option>
|
||||
<option value="" {% if not field.string_value %}selected{% endif %}>--------</option>
|
||||
{% endif %}
|
||||
{% for select in field.iter_options %}
|
||||
{% if select.start_option_group %}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
{% endif %}
|
||||
|
||||
<div class="col-sm-10">
|
||||
<textarea name="{{ field.name }}" class="form-control" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if style.rows %}rows="{{ style.rows }}"{% endif %}>{% if field.value %}{{ field.value }}{% endif %}</textarea>
|
||||
<textarea name="{{ field.name }}" class="form-control" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if style.rows %}rows="{{ style.rows }}"{% endif %}>{% if field.string_value %}{{ field.string_value }}{% endif %}</textarea>
|
||||
|
||||
{% if field.errors %}
|
||||
{% for error in field.errors %}
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
</label>
|
||||
{% endif %}
|
||||
|
||||
<input name="{{ field.name }}" {% if style.input_type != "file" %}class="form-control"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.value %}value="{{ field.value }}"{% endif %}>
|
||||
<input name="{{ field.name }}" {% if style.input_type != "file" %}class="form-control"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.string_value %}value="{{ field.string_value }}"{% endif %}>
|
||||
</div>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<select class="form-control" name="{{ field.name }}">
|
||||
{% if field.allow_null or field.allow_blank %}
|
||||
<option value="" {% if not field.value %}selected{% endif %}>--------</option>
|
||||
<option value="" {% if not field.string_value %}selected{% endif %}>--------</option>
|
||||
{% endif %}
|
||||
{% for select in field.iter_options %}
|
||||
{% if select.start_option_group %}
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
</label>
|
||||
{% endif %}
|
||||
|
||||
<input name="{{ field.name }}" type="text" class="form-control" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.value %}value="{{ field.value }}"{% endif %}>
|
||||
<input name="{{ field.name }}" type="text" class="form-control" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.string_value %}value="{{ field.string_value }}"{% endif %}>
|
||||
</div>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<label {% if style.hide_label %}class="sr-only"{% endif %}>{{ field.label }}</label>
|
||||
{% endif %}
|
||||
|
||||
<input name="{{ field.name }}" {% if style.input_type != "file" %}class="form-control"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.value %}value="{{ field.value }}"{% endif %}>
|
||||
<input name="{{ field.name }}" {% if style.input_type != "file" %}class="form-control"{% endif %} type="{{ style.input_type }}" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if field.string_value %}value="{{ field.string_value }}"{% endif %}>
|
||||
|
||||
{% if field.errors %}
|
||||
{% for error in field.errors %}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<select class="form-control" name="{{ field.name }}">
|
||||
{% if field.allow_null or field.allow_blank %}
|
||||
<option value="" {% if not field.value %}selected{% endif %}>--------</option>
|
||||
<option value="" {% if not field.string_value %}selected{% endif %}>--------</option>
|
||||
{% endif %}
|
||||
{% for select in field.iter_options %}
|
||||
{% if select.start_option_group %}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</label>
|
||||
{% endif %}
|
||||
|
||||
<textarea name="{{ field.name }}" class="form-control" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if style.rows %}rows="{{ style.rows }}"{% endif %}>{% if field.value %}{{ field.value }}{% endif %}</textarea>
|
||||
<textarea name="{{ field.name }}" class="form-control" {% if style.placeholder %}placeholder="{{ style.placeholder }}"{% endif %} {% if style.rows %}rows="{{ style.rows }}"{% endif %}>{% if field.string_value %}{{ field.string_value }}{% endif %}</textarea>
|
||||
|
||||
{% if field.errors %}
|
||||
{% for error in field.errors %}<span class="help-block">{{ error }}</span>{% endfor %}
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user