aboutsummaryrefslogtreecommitdiffstats
path: root/rest_framework
diff options
context:
space:
mode:
authorTom Christie2014-10-01 19:44:46 +0100
committerTom Christie2014-10-01 19:44:46 +0100
commitc171fa21ac62538331755524057d2435f33ec8a5 (patch)
tree518aea7774ca22b5836cad23090d18f968d35665 /rest_framework
parentc630a12e26f29145784523dd1b01ab0b3576f42c (diff)
downloaddjango-rest-framework-c171fa21ac62538331755524057d2435f33ec8a5.tar.bz2
First pass at HTML form rendering
Diffstat (limited to 'rest_framework')
-rw-r--r--rest_framework/renderers.py47
-rw-r--r--rest_framework/serializers.py2
-rw-r--r--rest_framework/templates/rest_framework/fields/attrs.html1
-rw-r--r--rest_framework/templates/rest_framework/fields/horizontal/checkbox.html10
-rw-r--r--rest_framework/templates/rest_framework/fields/horizontal/fieldset.html10
-rw-r--r--rest_framework/templates/rest_framework/fields/horizontal/input.html7
-rw-r--r--rest_framework/templates/rest_framework/fields/horizontal/label.html1
-rw-r--r--rest_framework/templates/rest_framework/fields/horizontal/select.html10
-rw-r--r--rest_framework/templates/rest_framework/fields/horizontal/select_checkbox.html22
-rw-r--r--rest_framework/templates/rest_framework/fields/horizontal/select_multiple.html10
-rw-r--r--rest_framework/templates/rest_framework/fields/horizontal/select_radio.html22
-rw-r--r--rest_framework/templates/rest_framework/fields/horizontal/textarea.html7
-rw-r--r--rest_framework/templates/rest_framework/fields/inline/checkbox.html6
-rw-r--r--rest_framework/templates/rest_framework/fields/inline/fieldset.html3
-rw-r--r--rest_framework/templates/rest_framework/fields/inline/input.html4
-rw-r--r--rest_framework/templates/rest_framework/fields/inline/label.html1
-rw-r--r--rest_framework/templates/rest_framework/fields/inline/select.html8
-rw-r--r--rest_framework/templates/rest_framework/fields/inline/select_checkbox.html11
-rw-r--r--rest_framework/templates/rest_framework/fields/inline/select_multiple.html8
-rw-r--r--rest_framework/templates/rest_framework/fields/inline/select_radio.html11
-rw-r--r--rest_framework/templates/rest_framework/fields/inline/textarea.html4
-rw-r--r--rest_framework/templates/rest_framework/fields/vertical/checkbox.html6
-rw-r--r--rest_framework/templates/rest_framework/fields/vertical/fieldset.html6
-rw-r--r--rest_framework/templates/rest_framework/fields/vertical/input.html5
-rw-r--r--rest_framework/templates/rest_framework/fields/vertical/label.html1
-rw-r--r--rest_framework/templates/rest_framework/fields/vertical/select.html8
-rw-r--r--rest_framework/templates/rest_framework/fields/vertical/select_checkbox.html22
-rw-r--r--rest_framework/templates/rest_framework/fields/vertical/select_multiple.html8
-rw-r--r--rest_framework/templates/rest_framework/fields/vertical/select_radio.html22
-rw-r--r--rest_framework/templates/rest_framework/fields/vertical/textarea.html5
-rw-r--r--rest_framework/templates/rest_framework/form.html40
-rw-r--r--rest_framework/templatetags/rest_framework.py8
-rw-r--r--rest_framework/utils/field_mapping.py3
33 files changed, 324 insertions, 15 deletions
diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py
index 225f9fe8..6483a47c 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 0faa5671..5da81247 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 00000000..b5a4dbcf
--- /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 00000000..dce4a5cf
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/checkbox.html
@@ -0,0 +1,10 @@
+<div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <div class="checkbox">
+ <label>
+ <input type="checkbox" name="{{ field.field_name }}" value="true" {% if value %}checked{% endif %}>
+ {% if field.label %}{{ field.label }}{% endif %}
+ </label>
+ </div>
+ </div>
+</div>
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 00000000..86417633
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/fieldset.html
@@ -0,0 +1,10 @@
+<fieldset>
+ {% if field.label %}
+ <div class="form-group" style="border-bottom: 1px solid #e5e5e5">
+ <legend class="control-label col-sm-2 {% if field.style.hide_label %}sr-only{% endif %}" style="border-bottom: 0">{{ field.label }}</legend>
+ </div>
+ {% endif %}
+ {% for field_item in value.field_items.values() %}
+ {{ renderer.render_field(field_item, layout=layout) }}
+ {% endfor %}
+</fieldset>
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 00000000..310154bb
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/input.html
@@ -0,0 +1,7 @@
+<div class="form-group">
+ {% include "rest_framework/fields/horizontal/label.html" %}
+ <div class="col-sm-10">
+ <input type="{{ input_type }}" class="form-control" {% include "rest_framework/fields/attrs.html" %} {% if value %}value="{{ value }}"{% endif %}>
+ {% if field.help_text %}<p class="help-block">{{ field.help_text }}</p>{% endif %}
+ </div>
+</div>
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 00000000..bf21f78c
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/label.html
@@ -0,0 +1 @@
+{% if field.label %}<label class="col-sm-2 control-label {% if field.style.hide_label %}sr-only{% endif %}">{{ field.label }}</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 00000000..3f8cab0a
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/select.html
@@ -0,0 +1,10 @@
+<div class="form-group">
+ {% include "rest_framework/fields/horizontal/label.html" %}
+ <div class="col-sm-10">
+ <select class="form-control" name="{{ field.field_name }}">
+ {% for key, text in field.choices.items %}
+ <option value="{{ key }}" {% if key == value %}selected{% endif %}>{{ text }}</option>
+ {% endfor %}
+ </select>
+ </div>
+</div>
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 00000000..659eede8
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/select_checkbox.html
@@ -0,0 +1,22 @@
+<div class="form-group">
+ {% include "rest_framework/fields/horizontal/label.html" %}
+ <div class="col-sm-10">
+ {% if field.style.inline %}
+ {% for key, text in field.choices.items %}
+ <label class="checkbox-inline">
+ <input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in value %}checked{% endif %}>
+ {{ text }}
+ </label>
+ {% endfor %}
+ {% else %}
+ {% for key, text in field.choices.items %}
+ <div class="checkbox">
+ <label>
+ <input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in value %}checked{% endif %}>
+ {{ text }}
+ </label>
+ </div>
+ {% endfor %}
+ {% endif %}
+ </div>
+</div>
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 00000000..da25eb2b
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/select_multiple.html
@@ -0,0 +1,10 @@
+<div class="form-group">
+ {% include "rest_framework/fields/horizontal/label.html" %}
+ <div class="col-sm-10">
+ <select multiple class="form-control" name="{{ field.field_name }}">
+ {% for key, text in field.choices.items %}
+ <option value="{{ key }}" {% if key in value %}selected{% endif %}>{{ text }}</option>
+ {% endfor %}
+ </select>
+ </div>
+</div>
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 00000000..188f05e2
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/select_radio.html
@@ -0,0 +1,22 @@
+<div class="form-group">
+ {% include "rest_framework/fields/horizontal/label.html" %}
+ <div class="col-sm-10">
+ {% if field.style.inline %}
+ {% for key, text in field.choices.items %}
+ <label class="radio-inline">
+ <input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == value %}checked{% endif %}>
+ {{ text }}
+ </label>
+ {% endfor %}
+ {% else %}
+ {% for key, text in field.choices.items %}
+ <div class="radio">
+ <label>
+ <input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == value %}checked{% endif %}>
+ {{ text }}
+ </label>
+ </div>
+ {% endfor %}
+ {% endif %}
+ </div>
+</div>
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 00000000..e99266f3
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/horizontal/textarea.html
@@ -0,0 +1,7 @@
+<div class="form-group">
+ {% include "rest_framework/fields/horizontal/label.html" %}
+ <div class="col-sm-10">
+ <textarea class="form-control" {% include "rest_framework/fields/attrs.html" %}>{% if value %}{{ value }}{% endif %}</textarea>
+ {% if field.help_text %}<p class="help-block">{{ field.help_text }}</p>{% endif %}
+ </div>
+</div>
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 00000000..01d30aae
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/checkbox.html
@@ -0,0 +1,6 @@
+<div class="checkbox">
+ <label>
+ <input type="checkbox" name="{{ field.field_name }}" value="true" {% if value %}checked{% endif %}>
+ {% if field.label %}{{ field.label }}{% endif %}
+ </label>
+</div>
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 00000000..d22982fd
--- /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 00000000..aefd1672
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/input.html
@@ -0,0 +1,4 @@
+<div class="form-group">
+ {% include "rest_framework/fields/inline/label.html" %}
+ <input type="{{ input_type }}" class="form-control" {% include "rest_framework/fields/attrs.html" %} {% if value %}value="{{ value }}"{% endif %}>
+</div>
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 00000000..7d546a57
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/label.html
@@ -0,0 +1 @@
+{% if field.label %}<label class="sr-only">{{ field.label }}</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 00000000..cb9a7013
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/select.html
@@ -0,0 +1,8 @@
+<div class="form-group">
+ {% include "rest_framework/fields/inline/label.html" %}
+ <select class="form-control" name="{{ field.field_name }}">
+ {% for key, text in field.choices.items %}
+ <option value="{{ key }}" {% if key == value %}selected{% endif %}>{{ text }}</option>
+ {% endfor %}
+ </select>
+</div>
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 00000000..424df93e
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/select_checkbox.html
@@ -0,0 +1,11 @@
+<div class="form-group">
+ {% include "rest_framework/fields/inline/label.html" %}
+ {% for key, text in field.choices.items %}
+ <div class="checkbox">
+ <label>
+ <input type="checkbox" name="{{ rest_framework/field.field_name }}" value="{{ key }}" {% if key in value %}checked{% endif %}>
+ {{ text }}
+ </label>
+ </div>
+ {% endfor %}
+</div>
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 00000000..6fdfd672
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/select_multiple.html
@@ -0,0 +1,8 @@
+<div class="form-group">
+ {% include "rest_framework/fields/inline/label.html" %}
+ <select multiple class="form-control" name="{{ field.field_name }}">
+ {% for key, text in field.choices.items %}
+ <option value="{{ key }}" {% if key in value %}selected{% endif %}>{{ text }}</option>
+ {% endfor %}
+ </select>
+</div>
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 00000000..ddabc9e9
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/select_radio.html
@@ -0,0 +1,11 @@
+<div class="form-group">
+ {% include "rest_framework/fields/inline/label.html" %}
+ {% for key, text in field.choices.items %}
+ <div class="radio">
+ <label>
+ <input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == value %}checked{% endif %}>
+ {{ text }}
+ </label>
+ </div>
+ {% endfor %}
+</div>
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 00000000..31366809
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/inline/textarea.html
@@ -0,0 +1,4 @@
+<div class="form-group">
+ {% include "rest_framework/fields/inline/label.html" %}
+ <textarea class="form-control" {% include "rest_framework/fields/attrs.html" %}>{% if value %}{{ value }}{% endif %}</textarea>
+</div>
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 00000000..01d30aae
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/checkbox.html
@@ -0,0 +1,6 @@
+<div class="checkbox">
+ <label>
+ <input type="checkbox" name="{{ field.field_name }}" value="true" {% if value %}checked{% endif %}>
+ {% if field.label %}{{ field.label }}{% endif %}
+ </label>
+</div>
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 00000000..cad32df9
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/fieldset.html
@@ -0,0 +1,6 @@
+<fieldset>
+ {% if field.label %}<legend {% if field.style.hide_label %}class="sr-only"{% endif %}>{{ field.label }}</legend>{% endif %}
+ {% for field_item in value.field_items.values() %}
+ {{ renderer.render_field(field_item, layout=layout) }}
+ {% endfor %}
+</fieldset>
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 00000000..c25407d1
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/input.html
@@ -0,0 +1,5 @@
+<div class="form-group">
+ {% include "rest_framework/fields/vertical/label.html" %}
+ <input type="{{ input_type }}" class="form-control" {% include "rest_framework/fields/attrs.html" %} {% if value %}value="{{ value }}"{% endif %}>
+ {% if field.help_text %}<p class="help-block">{{ field.help_text }}</p>{% endif %}
+</div>
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 00000000..651939b2
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/label.html
@@ -0,0 +1 @@
+{% if field.label %}<label {% if field.style.hide_label %}class="sr-only"{% endif %}>{{ field.label }}</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 00000000..44679d8a
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/select.html
@@ -0,0 +1,8 @@
+<div class="form-group">
+ {% include "rest_framework/fields/vertical/label.html" %}
+ <select class="form-control" name="{{ field.field_name }}">
+ {% for key, text in field.choices.items %}
+ <option value="{{ key }}" {% if key == value %}selected{% endif %}>{{ text }}</option>
+ {% endfor %}
+ </select>
+</div>
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 00000000..e60574c0
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/select_checkbox.html
@@ -0,0 +1,22 @@
+<div class="form-group">
+ {% include "rest_framework/fields/vertical/label.html" %}
+ {% if field.style.inline %}
+ <div>
+ {% for key, text in field.choices.items %}
+ <label class="checkbox-inline">
+ <input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in value %}checked{% endif %}>
+ {{ text }}
+ </label>
+ {% endfor %}
+ </div>
+ {% else %}
+ {% for key, text in field.choices.items %}
+ <div class="checkbox">
+ <label>
+ <input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in value %}checked{% endif %}>
+ {{ text }}
+ </label>
+ </div>
+ {% endfor %}
+ {% endif %}
+</div>
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 00000000..f0fa418b
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/select_multiple.html
@@ -0,0 +1,8 @@
+<div class="form-group">
+ {% include "rest_framework/fields/vertical/label.html" %}
+ <select multiple class="form-control" name="{{ field.field_name }}">
+ {% for key, text in field.choices.items() %}
+ <option value="{{ key }}" {% if key in value %}selected{% endif %}>{{ text }}</option>
+ {% endfor %}
+ </select>
+</div>
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 00000000..4ffe38ea
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/select_radio.html
@@ -0,0 +1,22 @@
+<div class="form-group">
+ {% include "rest_framework/fields/vertical/label.html" %}
+ {% if field.style.inline %}
+ <div>
+ {% for key, text in field.choices.items %}
+ <label class="radio-inline">
+ <input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key|string==value|string %}checked{% endif %}>
+ {{ text }}
+ </label>
+ {% endfor %}
+ </div>
+ {% else %}
+ {% for key, text in field.choices.items %}
+ <div class="radio">
+ <label>
+ <input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key|string==value|string %}checked{% endif %}>
+ {{ text }}
+ </label>
+ </div>
+ {% endfor %}
+ {% endif %}
+</div>
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 00000000..33cb27c7
--- /dev/null
+++ b/rest_framework/templates/rest_framework/fields/vertical/textarea.html
@@ -0,0 +1,5 @@
+<div class="form-group">
+ {% include "rest_framework/fields/vertical/label.html" %}
+ <textarea class="form-control" {% include "rest_framework/fields/attrs.html" %}>{% if value %}{{ value }}{% endif %}</textarea>
+ {% if field.help_text %}<p class="help-block">{{ field.help_text }}</p>{% endif %}
+</div>
diff --git a/rest_framework/templates/rest_framework/form.html b/rest_framework/templates/rest_framework/form.html
index b1e148df..64b1b0bc 100644
--- a/rest_framework/templates/rest_framework/form.html
+++ b/rest_framework/templates/rest_framework/form.html
@@ -1,15 +1,31 @@
+<html>
+<head>
+ <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
+</head>
+<body>
+<div class="container">
+
+<h1>User update</h1>
+<div class="well">
+
{% load rest_framework %}
-{% csrf_token %}
-{{ form.non_field_errors }}
-{% for field in form.fields.values %}
- {% if not field.read_only %}
- <div class="control-group {% if field.errors %}error{% endif %}">
- {{ field.label_tag|add_class:"control-label" }}
- <div class="controls">
- {{ field.widget_html }}
- {% if field.help_text %}<span class="help-block">{{ field.help_text }}</span>{% endif %}
- {% for error in field.errors %}<span class="help-block">{{ error }}</span>{% endfor %}
+<form {% if layout == "inline" %}class="form-inline"{% elif layout == "horizontal" %}class="form-horizontal"{% endif %} role="form" action="" method="POST">
+ {% csrf_token %}
+ {% for field, value, errors in form %}
+ {% render_field field value errors layout=layout renderer=renderer %}
+ {% endfor %}
+ <!-- form.non_field_errors -->
+ {% if layout == "horizontal" %}
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <button type="submit" class="btn btn-default">Submit</button>
+ </div>
</div>
- </div>
+ {% else %}
+ <button type="submit" class="btn btn-default">Submit</button>
{% endif %}
-{% endfor %}
+</form>
+
+</div>
+</div></body>
+</html>
diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py
index 864d64dd..88ff9d4e 100644
--- a/rest_framework/templatetags/rest_framework.py
+++ b/rest_framework/templatetags/rest_framework.py
@@ -31,6 +31,14 @@ class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])')
# And the template tags themselves...
+# @register.simple_tag
+# def render_field(field, value, errors, renderer):
+# return renderer.render_field(field, value, errors)
+@register.simple_tag
+def render_field(field, value, errors, layout=None, renderer=None):
+ return renderer.render_field(field, value, errors, layout)
+
+
@register.simple_tag
def optional_login(request):
"""
diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py
index cf9d910a..b4d33e39 100644
--- a/rest_framework/utils/field_mapping.py
+++ b/rest_framework/utils/field_mapping.py
@@ -79,6 +79,9 @@ def get_field_kwargs(field_name, model_field):
kwargs['choices'] = model_field.flatchoices
return kwargs
+ if isinstance(model_field, models.TextField):
+ kwargs['style'] = {'type': 'textarea'}
+
if model_field.null and not isinstance(model_field, models.NullBooleanField):
kwargs['allow_null'] = True