aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Christie2013-10-02 16:13:34 +0100
committerTom Christie2013-10-02 16:13:34 +0100
commit8d4ba478cc5725b4de6ab86b4825b1ea94cb4c7b (patch)
tree75187b1e1d5bd77dd4f137b467da5ce7a5b09603
parenta14f1e886402b8d0f742fdbb912b03a4004e1735 (diff)
downloaddjango-rest-framework-8d4ba478cc5725b4de6ab86b4825b1ea94cb4c7b.tar.bz2
Fix rendering of forms and add error rendering on HTML form
-rw-r--r--rest_framework/renderers.py16
-rw-r--r--rest_framework/serializers.py26
-rw-r--r--rest_framework/templates/rest_framework/base.html4
-rw-r--r--rest_framework/templates/rest_framework/raw_data_form.html12
4 files changed, 39 insertions, 19 deletions
diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py
index 0e17edaf..fe4f43d4 100644
--- a/rest_framework/renderers.py
+++ b/rest_framework/renderers.py
@@ -419,6 +419,13 @@ class BrowsableAPIRenderer(BaseRenderer):
In the absence of the View having an associated form then return None.
"""
+ if request.method == method:
+ data = request.DATA
+ files = request.FILES
+ else:
+ data = None
+ files = None
+
with override_method(view, request, method) as request:
obj = getattr(view, 'object', None)
if not self.show_form_for_method(view, method, request, obj):
@@ -431,9 +438,10 @@ class BrowsableAPIRenderer(BaseRenderer):
or not any(is_form_media_type(parser.media_type) for parser in view.parser_classes)):
return
- serializer = view.get_serializer(instance=obj)
-
+ serializer = view.get_serializer(instance=obj, data=data, files=files)
+ serializer.is_valid()
data = serializer.data
+
form_renderer = self.form_renderer_class()
return form_renderer.render(data, self.accepted_media_type, self.renderer_context)
@@ -525,6 +533,7 @@ class BrowsableAPIRenderer(BaseRenderer):
renderer = self.get_default_renderer(view)
+ raw_data_post_form = self.get_raw_data_form(view, 'POST', request)
raw_data_put_form = self.get_raw_data_form(view, 'PUT', request)
raw_data_patch_form = self.get_raw_data_form(view, 'PATCH', request)
raw_data_put_or_patch_form = raw_data_put_form or raw_data_patch_form
@@ -543,12 +552,11 @@ class BrowsableAPIRenderer(BaseRenderer):
'put_form': self.get_rendered_html_form(view, 'PUT', request),
'post_form': self.get_rendered_html_form(view, 'POST', request),
- 'patch_form': self.get_rendered_html_form(view, 'PATCH', request),
'delete_form': self.get_rendered_html_form(view, 'DELETE', request),
'options_form': self.get_rendered_html_form(view, 'OPTIONS', request),
'raw_data_put_form': raw_data_put_form,
- 'raw_data_post_form': self.get_raw_data_form(view, 'POST', request),
+ 'raw_data_post_form': raw_data_post_form,
'raw_data_patch_form': raw_data_patch_form,
'raw_data_put_or_patch_form': raw_data_put_or_patch_form,
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index 206a8123..bc9f73d1 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -308,24 +308,14 @@ class BaseSerializer(WritableField):
"""
ret = self._dict_class()
ret.fields = self._dict_class()
- ret.empty = obj is None
for field_name, field in self.fields.items():
field.initialize(parent=self, field_name=field_name)
key = self.get_field_key(field_name)
- if self._errors:
- value = self.init_data.get(field_name)
- else:
- value = field.field_to_native(obj, field_name)
-
- field._errors = self._errors.get(key) if self._errors else None
- field._name = field_name
- field._value = value
- if not field.label:
- field.label = pretty_name(key)
-
+ value = field.field_to_native(obj, field_name)
ret[key] = value
- ret.fields[key] = field
+ ret.fields[key] = self.augment_field(field, field_name, key, value)
+
return ret
def from_native(self, data, files):
@@ -333,6 +323,7 @@ class BaseSerializer(WritableField):
Deserialize primitives -> objects.
"""
self._errors = {}
+
if data is not None or files is not None:
attrs = self.restore_fields(data, files)
if attrs is not None:
@@ -343,6 +334,15 @@ class BaseSerializer(WritableField):
if not self._errors:
return self.restore_object(attrs, instance=getattr(self, 'object', None))
+ def augment_field(self, field, field_name, key, value):
+ # This horrible stuff is to manage serializers rendering to HTML
+ field._errors = self._errors.get(key) if self._errors else None
+ field._name = field_name
+ field._value = self.init_data.get(key) if self._errors and self.init_data else value
+ if not field.label:
+ field.label = pretty_name(key)
+ return field
+
def field_to_native(self, obj, field_name):
"""
Override default so that the serializer can be used as a nested field
diff --git a/rest_framework/templates/rest_framework/base.html b/rest_framework/templates/rest_framework/base.html
index 2776d550..33be36db 100644
--- a/rest_framework/templates/rest_framework/base.html
+++ b/rest_framework/templates/rest_framework/base.html
@@ -151,7 +151,7 @@
{% with form=raw_data_post_form %}
<form action="{{ request.get_full_path }}" method="POST" class="form-horizontal">
<fieldset>
- {% include "rest_framework/form.html" %}
+ {% include "rest_framework/raw_data_form.html" %}
<div class="form-actions">
<button class="btn btn-primary" title="Make a POST request on the {{ name }} resource">POST</button>
</div>
@@ -188,7 +188,7 @@
{% with form=raw_data_put_or_patch_form %}
<form action="{{ request.get_full_path }}" method="POST" class="form-horizontal">
<fieldset>
- {% include "rest_framework/form.html" %}
+ {% include "rest_framework/raw_data_form.html" %}
<div class="form-actions">
{% if raw_data_put_form %}
<button class="btn btn-primary js-tooltip" name="{{ api_settings.FORM_METHOD_OVERRIDE }}" value="PUT" title="Make a PUT request on the {{ name }} resource">PUT</button>
diff --git a/rest_framework/templates/rest_framework/raw_data_form.html b/rest_framework/templates/rest_framework/raw_data_form.html
new file mode 100644
index 00000000..075279f7
--- /dev/null
+++ b/rest_framework/templates/rest_framework/raw_data_form.html
@@ -0,0 +1,12 @@
+{% load rest_framework %}
+{% csrf_token %}
+{{ form.non_field_errors }}
+{% for field in form %}
+ <div class="control-group">
+ {{ field.label_tag|add_class:"control-label" }}
+ <div class="controls">
+ {{ field }}
+ <span class="help-block">{{ field.help_text }}</span>
+ </div>
+ </div>
+{% endfor %}