diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py
index 225f9fe8f..6483a47c0 100644
--- a/rest_framework/renderers.py
+++ b/rest_framework/renderers.py
@@ -13,17 +13,18 @@ import django
from django import forms
from django.core.exceptions import ImproperlyConfigured
from django.http.multipartparser import parse_header
-from django.template import RequestContext, loader, Template
+from django.template import Context, RequestContext, loader, Template
from django.test.client import encode_multipart
from django.utils import six
from django.utils.xmlutils import SimplerXMLGenerator
+from rest_framework import exceptions, serializers, status, VERSION
from rest_framework.compat import StringIO, smart_text, yaml
from rest_framework.exceptions import ParseError
from rest_framework.settings import api_settings
from rest_framework.request import is_form_media_type, override_method
from rest_framework.utils import encoders
from rest_framework.utils.breadcrumbs import get_breadcrumbs
-from rest_framework import exceptions, status, VERSION
+from rest_framework.utils.field_mapping import ClassLookupDict
def zero_as_none(value):
@@ -341,6 +342,42 @@ class HTMLFormRenderer(BaseRenderer):
template = 'rest_framework/form.html'
charset = 'utf-8'
+ field_templates = ClassLookupDict({
+ serializers.Field: {
+ 'default': 'input.html'
+ },
+ serializers.BooleanField: {
+ 'default': 'checkbox.html'
+ },
+ serializers.CharField: {
+ 'default': 'input.html',
+ 'textarea': 'textarea.html'
+ },
+ serializers.ChoiceField: {
+ 'default': 'select.html',
+ 'radio': 'select_radio.html'
+ },
+ serializers.MultipleChoiceField: {
+ 'default': 'select_multiple.html',
+ 'checkbox': 'select_checkbox.html'
+ }
+ })
+
+ def render_field(self, field, value, errors, layout=None):
+ layout = layout or 'vertical'
+ style_type = field.style.get('type', 'default')
+ if style_type == 'textarea' and layout == 'inline':
+ style_type = 'default'
+ base = self.field_templates[field][style_type]
+ template_name = 'rest_framework/fields/' + layout + '/' + base
+ template = loader.get_template(template_name)
+ context = Context({
+ 'field': field,
+ 'value': value,
+ 'errors': errors
+ })
+ return template.render(context)
+
def render(self, data, accepted_media_type=None, renderer_context=None):
"""
Render serializer data and return an HTML form, as a string.
@@ -349,7 +386,11 @@ class HTMLFormRenderer(BaseRenderer):
request = renderer_context['request']
template = loader.get_template(self.template)
- context = RequestContext(request, {'form': data})
+ context = RequestContext(request, {
+ 'form': data,
+ 'layout': getattr(getattr(data, 'Meta', None), 'layout', 'vertical'),
+ 'renderer': self
+ })
return template.render(context)
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index 0faa56718..5da812477 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -302,6 +302,8 @@ class Serializer(BaseSerializer):
def __iter__(self):
errors = self.errors if hasattr(self, '_errors') else {}
for field in self.fields.values():
+ if field.read_only:
+ continue
value = self.data.get(field.field_name) if self.data else None
error = errors.get(field.field_name)
yield FieldResult(field, value, error)
diff --git a/rest_framework/templates/rest_framework/fields/attrs.html b/rest_framework/templates/rest_framework/fields/attrs.html
new file mode 100644
index 000000000..b5a4dbcf1
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/attrs.html
@@ -0,0 +1 @@
+name="{{ field.field_name }}" {% if field.style.placeholder %}placeholder="{{ field.style.placeholder }}"{% endif %} {% if field.style.rows %}rows="{{ field.style.rows }}"{% endif %}
diff --git a/rest_framework/templates/rest_framework/fields/horizontal/checkbox.html b/rest_framework/templates/rest_framework/fields/horizontal/checkbox.html
new file mode 100644
index 000000000..dce4a5cf9
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/checkbox.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/rest_framework/templates/rest_framework/fields/horizontal/fieldset.html b/rest_framework/templates/rest_framework/fields/horizontal/fieldset.html
new file mode 100644
index 000000000..86417633f
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/fieldset.html
@@ -0,0 +1,10 @@
+
diff --git a/rest_framework/templates/rest_framework/fields/horizontal/input.html b/rest_framework/templates/rest_framework/fields/horizontal/input.html
new file mode 100644
index 000000000..310154bb4
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/input.html
@@ -0,0 +1,7 @@
+
+ {% include "rest_framework/fields/horizontal/label.html" %}
+
+
+ {% if field.help_text %}
{{ field.help_text }}
{% endif %}
+
+
diff --git a/rest_framework/templates/rest_framework/fields/horizontal/label.html b/rest_framework/templates/rest_framework/fields/horizontal/label.html
new file mode 100644
index 000000000..bf21f78cc
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/label.html
@@ -0,0 +1 @@
+{% if field.label %}{% endif %}
diff --git a/rest_framework/templates/rest_framework/fields/horizontal/select.html b/rest_framework/templates/rest_framework/fields/horizontal/select.html
new file mode 100644
index 000000000..3f8cab0a3
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/select.html
@@ -0,0 +1,10 @@
+
+ {% include "rest_framework/fields/horizontal/label.html" %}
+
+
+
+
diff --git a/rest_framework/templates/rest_framework/fields/horizontal/select_checkbox.html b/rest_framework/templates/rest_framework/fields/horizontal/select_checkbox.html
new file mode 100644
index 000000000..659eede84
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/select_checkbox.html
@@ -0,0 +1,22 @@
+
+ {% include "rest_framework/fields/horizontal/label.html" %}
+
+ {% if field.style.inline %}
+ {% for key, text in field.choices.items %}
+
+ {% endfor %}
+ {% else %}
+ {% for key, text in field.choices.items %}
+
+
+
+ {% endfor %}
+ {% endif %}
+
+
diff --git a/rest_framework/templates/rest_framework/fields/horizontal/select_multiple.html b/rest_framework/templates/rest_framework/fields/horizontal/select_multiple.html
new file mode 100644
index 000000000..da25eb2bd
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/select_multiple.html
@@ -0,0 +1,10 @@
+
+ {% include "rest_framework/fields/horizontal/label.html" %}
+
+
+
+
diff --git a/rest_framework/templates/rest_framework/fields/horizontal/select_radio.html b/rest_framework/templates/rest_framework/fields/horizontal/select_radio.html
new file mode 100644
index 000000000..188f05e27
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/select_radio.html
@@ -0,0 +1,22 @@
+
+ {% include "rest_framework/fields/horizontal/label.html" %}
+
+ {% if field.style.inline %}
+ {% for key, text in field.choices.items %}
+
+ {% endfor %}
+ {% else %}
+ {% for key, text in field.choices.items %}
+
+
+
+ {% endfor %}
+ {% endif %}
+
+
diff --git a/rest_framework/templates/rest_framework/fields/horizontal/textarea.html b/rest_framework/templates/rest_framework/fields/horizontal/textarea.html
new file mode 100644
index 000000000..e99266f37
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/textarea.html
@@ -0,0 +1,7 @@
+
+ {% include "rest_framework/fields/horizontal/label.html" %}
+
+
+ {% if field.help_text %}
{{ field.help_text }}
{% endif %}
+
+
diff --git a/rest_framework/templates/rest_framework/fields/inline/checkbox.html b/rest_framework/templates/rest_framework/fields/inline/checkbox.html
new file mode 100644
index 000000000..01d30aaef
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/checkbox.html
@@ -0,0 +1,6 @@
+
+
+
diff --git a/rest_framework/templates/rest_framework/fields/inline/fieldset.html b/rest_framework/templates/rest_framework/fields/inline/fieldset.html
new file mode 100644
index 000000000..d22982fdd
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/fieldset.html
@@ -0,0 +1,3 @@
+{% for field_item in value.field_items.values() %}
+ {{ renderer.render_field(field_item, layout=layout) }}
+{% endfor %}
diff --git a/rest_framework/templates/rest_framework/fields/inline/input.html b/rest_framework/templates/rest_framework/fields/inline/input.html
new file mode 100644
index 000000000..aefd16723
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/input.html
@@ -0,0 +1,4 @@
+
+ {% include "rest_framework/fields/inline/label.html" %}
+
+
diff --git a/rest_framework/templates/rest_framework/fields/inline/label.html b/rest_framework/templates/rest_framework/fields/inline/label.html
new file mode 100644
index 000000000..7d546a571
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/label.html
@@ -0,0 +1 @@
+{% if field.label %}{% endif %}
diff --git a/rest_framework/templates/rest_framework/fields/inline/select.html b/rest_framework/templates/rest_framework/fields/inline/select.html
new file mode 100644
index 000000000..cb9a70137
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/select.html
@@ -0,0 +1,8 @@
+
+ {% include "rest_framework/fields/inline/label.html" %}
+
+
diff --git a/rest_framework/templates/rest_framework/fields/inline/select_checkbox.html b/rest_framework/templates/rest_framework/fields/inline/select_checkbox.html
new file mode 100644
index 000000000..424df93e6
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/select_checkbox.html
@@ -0,0 +1,11 @@
+
+ {% include "rest_framework/fields/inline/label.html" %}
+ {% for key, text in field.choices.items %}
+
+
+
+ {% endfor %}
+
diff --git a/rest_framework/templates/rest_framework/fields/inline/select_multiple.html b/rest_framework/templates/rest_framework/fields/inline/select_multiple.html
new file mode 100644
index 000000000..6fdfd672f
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/select_multiple.html
@@ -0,0 +1,8 @@
+
+ {% include "rest_framework/fields/inline/label.html" %}
+
+
diff --git a/rest_framework/templates/rest_framework/fields/inline/select_radio.html b/rest_framework/templates/rest_framework/fields/inline/select_radio.html
new file mode 100644
index 000000000..ddabc9e96
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/select_radio.html
@@ -0,0 +1,11 @@
+
+ {% include "rest_framework/fields/inline/label.html" %}
+ {% for key, text in field.choices.items %}
+
+
+
+ {% endfor %}
+
diff --git a/rest_framework/templates/rest_framework/fields/inline/textarea.html b/rest_framework/templates/rest_framework/fields/inline/textarea.html
new file mode 100644
index 000000000..313668098
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/textarea.html
@@ -0,0 +1,4 @@
+
+ {% include "rest_framework/fields/inline/label.html" %}
+
+
diff --git a/rest_framework/templates/rest_framework/fields/vertical/checkbox.html b/rest_framework/templates/rest_framework/fields/vertical/checkbox.html
new file mode 100644
index 000000000..01d30aaef
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/checkbox.html
@@ -0,0 +1,6 @@
+
+
+
diff --git a/rest_framework/templates/rest_framework/fields/vertical/fieldset.html b/rest_framework/templates/rest_framework/fields/vertical/fieldset.html
new file mode 100644
index 000000000..cad32df99
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/fieldset.html
@@ -0,0 +1,6 @@
+
diff --git a/rest_framework/templates/rest_framework/fields/vertical/input.html b/rest_framework/templates/rest_framework/fields/vertical/input.html
new file mode 100644
index 000000000..c25407d16
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/input.html
@@ -0,0 +1,5 @@
+
+ {% include "rest_framework/fields/vertical/label.html" %}
+
+ {% if field.help_text %}
{{ field.help_text }}
{% endif %}
+
diff --git a/rest_framework/templates/rest_framework/fields/vertical/label.html b/rest_framework/templates/rest_framework/fields/vertical/label.html
new file mode 100644
index 000000000..651939b26
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/label.html
@@ -0,0 +1 @@
+{% if field.label %}{% endif %}
diff --git a/rest_framework/templates/rest_framework/fields/vertical/select.html b/rest_framework/templates/rest_framework/fields/vertical/select.html
new file mode 100644
index 000000000..44679d8a4
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/select.html
@@ -0,0 +1,8 @@
+
+ {% include "rest_framework/fields/vertical/label.html" %}
+
+
diff --git a/rest_framework/templates/rest_framework/fields/vertical/select_checkbox.html b/rest_framework/templates/rest_framework/fields/vertical/select_checkbox.html
new file mode 100644
index 000000000..e60574c07
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/select_checkbox.html
@@ -0,0 +1,22 @@
+
+ {% include "rest_framework/fields/vertical/label.html" %}
+ {% if field.style.inline %}
+
+ {% for key, text in field.choices.items %}
+
+ {% endfor %}
+
+ {% else %}
+ {% for key, text in field.choices.items %}
+
+
+
+ {% endfor %}
+ {% endif %}
+
diff --git a/rest_framework/templates/rest_framework/fields/vertical/select_multiple.html b/rest_framework/templates/rest_framework/fields/vertical/select_multiple.html
new file mode 100644
index 000000000..f0fa418b5
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/select_multiple.html
@@ -0,0 +1,8 @@
+
+ {% include "rest_framework/fields/vertical/label.html" %}
+
+
diff --git a/rest_framework/templates/rest_framework/fields/vertical/select_radio.html b/rest_framework/templates/rest_framework/fields/vertical/select_radio.html
new file mode 100644
index 000000000..4ffe38ea9
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/select_radio.html
@@ -0,0 +1,22 @@
+
+ {% include "rest_framework/fields/vertical/label.html" %}
+ {% if field.style.inline %}
+
+ {% for key, text in field.choices.items %}
+
+ {% endfor %}
+
+ {% else %}
+ {% for key, text in field.choices.items %}
+
+
+
+ {% endfor %}
+ {% endif %}
+
diff --git a/rest_framework/templates/rest_framework/fields/vertical/textarea.html b/rest_framework/templates/rest_framework/fields/vertical/textarea.html
new file mode 100644
index 000000000..33cb27c75
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/textarea.html
@@ -0,0 +1,5 @@
+
+ {% include "rest_framework/fields/vertical/label.html" %}
+
+ {% if field.help_text %}