From 7d417fc67864fc4c1c340eeae276cea0d5d428b1 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 20 Nov 2014 12:02:58 +0000 Subject: [PATCH 1/4] Make _force_text_recursive private. --- rest_framework/exceptions.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/rest_framework/exceptions.py b/rest_framework/exceptions.py index dbab66842..906de3b04 100644 --- a/rest_framework/exceptions.py +++ b/rest_framework/exceptions.py @@ -13,6 +13,23 @@ from rest_framework.compat import force_text import math +def _force_text_recursive(data): + """ + Descend into a nested data structure, forcing any + lazy translation strings into plain text. + """ + if isinstance(data, list): + return [ + _force_text_recursive(item) for item in data + ] + elif isinstance(data, dict): + return dict([ + (key, _force_text_recursive(value)) + for key, value in data.items() + ]) + return force_text(data) + + class APIException(Exception): """ Base class for REST framework exceptions. @@ -38,19 +55,6 @@ class APIException(Exception): # from rest_framework import serializers # raise serializers.ValidationError('Value was invalid') -def force_text_recursive(data): - if isinstance(data, list): - return [ - force_text_recursive(item) for item in data - ] - elif isinstance(data, dict): - return dict([ - (key, force_text_recursive(value)) - for key, value in data.items() - ]) - return force_text(data) - - class ValidationError(APIException): status_code = status.HTTP_400_BAD_REQUEST @@ -59,7 +63,7 @@ class ValidationError(APIException): # The details should always be coerced to a list if not already. if not isinstance(detail, dict) and not isinstance(detail, list): detail = [detail] - self.detail = force_text_recursive(detail) + self.detail = _force_text_recursive(detail) def __str__(self): return str(self.detail) From 6794b3380a32b53fa88547a8b2a2b34834fe4df7 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 20 Nov 2014 12:15:33 +0000 Subject: [PATCH 2/4] Fixes for defaulting empty HTML fields to '', None, or empty. --- rest_framework/fields.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index bb43708dc..778bc7187 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -181,6 +181,9 @@ class Field(object): self.style = {} if style is None else style self.allow_null = allow_null + if allow_null and self.default_empty_html is empty: + self.default_empty_html = None + if validators is not None: self.validators = validators[:] @@ -495,6 +498,7 @@ class CharField(Field): } initial = '' coerce_blank_to_null = False + default_empty_html = '' def __init__(self, **kwargs): self.allow_blank = kwargs.pop('allow_blank', False) From 9c6bead8b6d3f9ae11e9859ed305e8d0f7a9e0d8 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 20 Nov 2014 12:38:08 +0000 Subject: [PATCH 3/4] Add --- null option for selects. Closes #2096. --- .../templates/rest_framework/horizontal/select.html | 3 +++ rest_framework/templates/rest_framework/inline/select.html | 5 ++++- rest_framework/templates/rest_framework/vertical/select.html | 5 ++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/rest_framework/templates/rest_framework/horizontal/select.html b/rest_framework/templates/rest_framework/horizontal/select.html index 1d00f4241..380b38e94 100644 --- a/rest_framework/templates/rest_framework/horizontal/select.html +++ b/rest_framework/templates/rest_framework/horizontal/select.html @@ -4,6 +4,9 @@ {% endif %}
+ {% if field.allow_null %} + + {% endif %} {% for key, text in field.choices.items %} - + {% endfor %}
diff --git a/rest_framework/templates/rest_framework/vertical/select.html b/rest_framework/templates/rest_framework/vertical/select.html index 7c673ebb5..de72e1ddb 100644 --- a/rest_framework/templates/rest_framework/vertical/select.html +++ b/rest_framework/templates/rest_framework/vertical/select.html @@ -3,8 +3,11 @@ {% endif %} {% if field.errors %} From 6ec96d0bac1e738aceec9f8c21282c172120c7ac Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 20 Nov 2014 13:43:38 +0000 Subject: [PATCH 4/4] Resolve PUT and POST buttons in browsable API --- rest_framework/renderers.py | 14 ++++++++++++-- .../templates/rest_framework/api_form.html | 8 ++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 rest_framework/templates/rest_framework/api_form.html diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 6596fc44c..8717137af 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -429,7 +429,10 @@ class HTMLFormRenderer(BaseRenderer): style['base_template'] = self.base_template style['renderer'] = self - if 'template' in style: + # This API needs to be finessed and finalized for 3.1 + if 'template' in renderer_context: + template_name = renderer_context['template'] + elif 'template' in style: template_name = style['template'] else: template_name = style['template_pack'].strip('/') + '/' + style['base_template'] @@ -555,7 +558,14 @@ class BrowsableAPIRenderer(BaseRenderer): if data is not None: serializer.is_valid() form_renderer = self.form_renderer_class() - return form_renderer.render(serializer.data, self.accepted_media_type, self.renderer_context) + return form_renderer.render( + serializer.data, + self.accepted_media_type, + dict( + self.renderer_context.items() + + [('template', 'rest_framework/api_form.html')] + ) + ) def get_raw_data_form(self, data, view, method, request): """ diff --git a/rest_framework/templates/rest_framework/api_form.html b/rest_framework/templates/rest_framework/api_form.html new file mode 100644 index 000000000..96f924ed8 --- /dev/null +++ b/rest_framework/templates/rest_framework/api_form.html @@ -0,0 +1,8 @@ +{% load rest_framework %} +{% csrf_token %} +{% for field in form %} + {% if not field.read_only %} + {% render_field field style=style %} + {% endif %} +{% endfor %} +