diff options
| author | Tom Christie | 2014-10-02 16:24:24 +0100 |
|---|---|---|
| committer | Tom Christie | 2014-10-02 16:24:24 +0100 |
| commit | df7b6fcf58417fd95e49655eb140b387899b1ceb (patch) | |
| tree | a4a7d932bb3ef7c8e326b0248662fd31edcc2658 /rest_framework | |
| parent | ffc6aa3abcb0f823b43b63db1666913565e6f934 (diff) | |
| download | django-rest-framework-df7b6fcf58417fd95e49655eb140b387899b1ceb.tar.bz2 | |
First pass on incorperating the form rendering into the browsable API
Diffstat (limited to 'rest_framework')
32 files changed, 217 insertions, 144 deletions
diff --git a/rest_framework/fields.py b/rest_framework/fields.py index f3ff2233..c794963e 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -689,10 +689,10 @@ class DateTimeField(Field): return value if self.format.lower() == ISO_8601: - ret = value.isoformat() - if ret.endswith('+00:00'): - ret = ret[:-6] + 'Z' - return ret + value = value.isoformat() + if value.endswith('+00:00'): + value = value[:-6] + 'Z' + return value return value.strftime(self.format) diff --git a/rest_framework/relations.py b/rest_framework/relations.py index 8c135672..988b9ede 100644 --- a/rest_framework/relations.py +++ b/rest_framework/relations.py @@ -127,7 +127,7 @@ class HyperlinkedRelatedField(RelatedField): attributes are not configured to correctly match the URL conf. """ # Unsaved objects will not yet have a valid URL. - if obj.pk is None: + if obj.pk: return None lookup_value = getattr(obj, self.lookup_field) @@ -248,11 +248,13 @@ class ManyRelation(Field): You shouldn't need to be using this class directly yourself. """ + initial = [] def __init__(self, child_relation=None, *args, **kwargs): self.child_relation = child_relation assert child_relation is not None, '`child_relation` is a required argument.' super(ManyRelation, self).__init__(*args, **kwargs) + self.child_relation.bind(field_name='', parent=self) def to_internal_value(self, data): return [ diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 297c60d8..931dd434 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -377,23 +377,21 @@ class HTMLFormRenderer(BaseRenderer): serializers.TimeField: 'time', }) - def render_field(self, field, value, errors, layout=None): + def render_field(self, field, layout=None): layout = layout or 'vertical' style_type = field.style.get('type', 'default') if style_type == 'textarea' and layout == 'inline': style_type = 'default' input_type = self.input_type[field] - if input_type == 'datetime-local': - value = value.rstrip('Z') + if input_type == 'datetime-local' and isinstance(field.value, six.text_type): + field.value = field.value.rstrip('Z') 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, 'input_type': input_type }) @@ -408,7 +406,7 @@ class HTMLFormRenderer(BaseRenderer): template = loader.get_template(self.template) context = RequestContext(request, { - 'form': data, + 'form': data.serializer, 'layout': getattr(getattr(data, 'Meta', None), 'layout', 'horizontal'), 'renderer': self }) @@ -479,27 +477,29 @@ class BrowsableAPIRenderer(BaseRenderer): return False # Doesn't have permissions return True - def get_rendered_html_form(self, view, method, request): + def get_rendered_html_form(self, data, view, method, request): """ Return a string representing a rendered HTML form, possibly bound to either the input or output data. In the absence of the View having an associated form then return None. """ + serializer = getattr(data, 'serializer', None) + if serializer and not getattr(serializer, 'many', False): + instance = getattr(serializer, 'instance', None) + else: + instance = None + if request.method == method: try: data = request.data - # files = request.FILES except ParseError: data = None - # files = None 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): + if not self.show_form_for_method(view, method, request, instance): return if method in ('DELETE', 'OPTIONS'): @@ -511,19 +511,24 @@ class BrowsableAPIRenderer(BaseRenderer): ): return - serializer = view.get_serializer(instance=obj, data=data) - serializer.is_valid() - data = serializer.data - + serializer = view.get_serializer(instance=instance, data=data) + if data is not None: + serializer.is_valid() form_renderer = self.form_renderer_class() - return form_renderer.render(data, self.accepted_media_type, self.renderer_context) + return form_renderer.render(serializer.data, self.accepted_media_type, self.renderer_context) - def get_raw_data_form(self, view, method, request): + def get_raw_data_form(self, data, view, method, request): """ Returns a form that allows for arbitrary content types to be tunneled via standard HTML forms. (Which are typically application/x-www-form-urlencoded) """ + serializer = getattr(data, 'serializer', None) + if serializer and not getattr(serializer, 'many', False): + instance = getattr(serializer, 'instance', None) + else: + instance = None + with override_method(view, request, method) as request: # If we're not using content overloading there's no point in # supplying a generic form, as the view won't treat the form's @@ -533,8 +538,7 @@ class BrowsableAPIRenderer(BaseRenderer): return None # Check permissions - obj = getattr(view, 'object', None) - if not self.show_form_for_method(view, method, request, obj): + if not self.show_form_for_method(view, method, request, instance): return # If possible, serialize the initial content for the generic form @@ -545,8 +549,8 @@ class BrowsableAPIRenderer(BaseRenderer): # corresponding renderer that can be used to render the data. # Get a read-only version of the serializer - serializer = view.get_serializer(instance=obj) - if obj is None: + serializer = view.get_serializer(instance=instance) + if instance is None: for name, field in serializer.fields.items(): if getattr(field, 'read_only', None): del serializer.fields[name] @@ -606,9 +610,9 @@ 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_post_form = self.get_raw_data_form(data, view, 'POST', request) + raw_data_put_form = self.get_raw_data_form(data, view, 'PUT', request) + raw_data_patch_form = self.get_raw_data_form(data, view, 'PATCH', request) raw_data_put_or_patch_form = raw_data_put_form or raw_data_patch_form response_headers = dict(response.items()) @@ -632,10 +636,10 @@ class BrowsableAPIRenderer(BaseRenderer): 'available_formats': [renderer_cls.format for renderer_cls in view.renderer_classes], 'response_headers': response_headers, - # 'put_form': self.get_rendered_html_form(view, 'PUT', request), - # 'post_form': self.get_rendered_html_form(view, 'POST', request), - # 'delete_form': self.get_rendered_html_form(view, 'DELETE', request), - # 'options_form': self.get_rendered_html_form(view, 'OPTIONS', request), + 'put_form': self.get_rendered_html_form(data, view, 'PUT', request), + 'post_form': self.get_rendered_html_form(data, view, 'POST', request), + 'delete_form': self.get_rendered_html_form(data, view, 'DELETE', request), + 'options_form': self.get_rendered_html_form(data, view, 'OPTIONS', request), 'raw_data_put_form': raw_data_put_form, 'raw_data_post_form': raw_data_post_form, diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 5da81247..0f24ed40 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -14,7 +14,6 @@ from django.core.exceptions import ImproperlyConfigured, ValidationError from django.db import models from django.utils import six from django.utils.datastructures import SortedDict -from collections import namedtuple from rest_framework.fields import empty, set_value, Field, SkipField from rest_framework.settings import api_settings from rest_framework.utils import html, model_meta, representation @@ -38,8 +37,8 @@ from rest_framework.relations import * # NOQA from rest_framework.fields import * # NOQA -FieldResult = namedtuple('FieldResult', ['field', 'value', 'error']) - +# BaseSerializer +# -------------- class BaseSerializer(Field): """ @@ -113,11 +112,6 @@ class BaseSerializer(Field): if not hasattr(self, '_data'): if self.instance is not None: self._data = self.to_representation(self.instance) - elif self._initial_data is not None: - self._data = dict([ - (field_name, field.get_value(self._initial_data)) - for field_name, field in self.fields.items() - ]) else: self._data = self.get_initial() return self._data @@ -137,34 +131,48 @@ class BaseSerializer(Field): return self._validated_data -class SerializerMetaclass(type): +# Serializer & ListSerializer classes +# ----------------------------------- + +class ReturnDict(SortedDict): """ - This metaclass sets a dictionary named `base_fields` on the class. + Return object from `serialier.data` for the `Serializer` class. + Includes a backlink to the serializer instance for renderers + to use if they need richer field information. + """ + def __init__(self, *args, **kwargs): + self.serializer = kwargs.pop('serializer') + super(ReturnDict, self).__init__(*args, **kwargs) - Any instances of `Field` included as attributes on either the class - or on any of its superclasses will be include in the - `base_fields` dictionary. + +class ReturnList(list): + """ + Return object from `serialier.data` for the `SerializerList` class. + Includes a backlink to the serializer instance for renderers + to use if they need richer field information. """ + def __init__(self, *args, **kwargs): + self.serializer = kwargs.pop('serializer') + super(ReturnList, self).__init__(*args, **kwargs) - @classmethod - def _get_declared_fields(cls, bases, attrs): - fields = [(field_name, attrs.pop(field_name)) - for field_name, obj in list(attrs.items()) - if isinstance(obj, Field)] - fields.sort(key=lambda x: x[1]._creation_counter) - # If this class is subclassing another Serializer, add that Serializer's - # fields. Note that we loop over the bases in *reverse*. This is necessary - # in order to maintain the correct order of fields. - for base in bases[::-1]: - if hasattr(base, '_declared_fields'): - fields = list(base._declared_fields.items()) + fields +class BoundField(object): + """ + A field object that also includes `.value` and `.error` properties. + Returned when iterating over a serializer instance, + providing an API similar to Django forms and form fields. + """ + def __init__(self, field, value, errors): + self._field = field + self.value = value + self.errors = errors - return SortedDict(fields) + def __getattr__(self, attr_name): + return getattr(self._field, attr_name) - def __new__(cls, name, bases, attrs): - attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs) - return super(SerializerMetaclass, cls).__new__(cls, name, bases, attrs) + @property + def _proxy_class(self): + return self._field.__class__ class BindingDict(object): @@ -196,6 +204,36 @@ class BindingDict(object): return self.fields.values() +class SerializerMetaclass(type): + """ + This metaclass sets a dictionary named `base_fields` on the class. + + Any instances of `Field` included as attributes on either the class + or on any of its superclasses will be include in the + `base_fields` dictionary. + """ + + @classmethod + def _get_declared_fields(cls, bases, attrs): + fields = [(field_name, attrs.pop(field_name)) + for field_name, obj in list(attrs.items()) + if isinstance(obj, Field)] + fields.sort(key=lambda x: x[1]._creation_counter) + + # If this class is subclassing another Serializer, add that Serializer's + # fields. Note that we loop over the bases in *reverse*. This is necessary + # in order to maintain the correct order of fields. + for base in bases[::-1]: + if hasattr(base, '_declared_fields'): + fields = list(base._declared_fields.items()) + fields + + return SortedDict(fields) + + def __new__(cls, name, bases, attrs): + attrs['_declared_fields'] = cls._get_declared_fields(bases, attrs) + return super(SerializerMetaclass, cls).__new__(cls, name, bases, attrs) + + @six.add_metaclass(SerializerMetaclass) class Serializer(BaseSerializer): def __init__(self, *args, **kwargs): @@ -212,10 +250,18 @@ class Serializer(BaseSerializer): return copy.deepcopy(self._declared_fields) def get_initial(self): - return dict([ + if self._initial_data is not None: + return ReturnDict([ + (field_name, field.get_value(self._initial_data)) + for field_name, field in self.fields.items() + ], serializer=self) + #return self.to_representation(self._initial_data) + + return ReturnDict([ (field.field_name, field.get_initial()) for field in self.fields.values() - ]) + if not field.write_only + ], serializer=self) def get_value(self, dictionary): # We override the default field access in order to support @@ -288,7 +334,7 @@ class Serializer(BaseSerializer): """ Object instance -> Dict of primitive datatypes. """ - ret = SortedDict() + ret = ReturnDict(serializer=self) fields = [field for field in self.fields.values() if not field.write_only] for field in fields: @@ -302,11 +348,9 @@ 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) + yield BoundField(field, value, error) def __repr__(self): return representation.serializer_repr(self, indent=1) @@ -317,7 +361,7 @@ class Serializer(BaseSerializer): class ListSerializer(BaseSerializer): child = None - initial = [] + many = True def __init__(self, *args, **kwargs): self.child = kwargs.pop('child', copy.deepcopy(self.child)) @@ -326,6 +370,11 @@ class ListSerializer(BaseSerializer): super(ListSerializer, self).__init__(*args, **kwargs) self.child.bind(field_name='', parent=self) + def get_initial(self): + if self._initial_data is not None: + return self.to_representation(self._initial_data) + return ReturnList(serializer=self) + def get_value(self, dictionary): # We override the default field access in order to support # lists in HTML forms. @@ -345,7 +394,10 @@ class ListSerializer(BaseSerializer): """ List of object instances -> List of dicts of primitive datatypes. """ - return [self.child.to_representation(item) for item in data] + return ReturnList( + [self.child.to_representation(item) for item in data], + serializer=self + ) def create(self, attrs_list): return [self.child.create(attrs) for attrs in attrs_list] @@ -354,6 +406,9 @@ class ListSerializer(BaseSerializer): return representation.list_repr(self, indent=1) +# ModelSerializer & HyperlinkedModelSerializer +# -------------------------------------------- + class ModelSerializer(Serializer): _field_mapping = ClassLookupDict({ models.AutoField: IntegerField, diff --git a/rest_framework/static/rest_framework/css/bootstrap-tweaks.css b/rest_framework/static/rest_framework/css/bootstrap-tweaks.css index 6fa1e6cb..84389b1d 100644 --- a/rest_framework/static/rest_framework/css/bootstrap-tweaks.css +++ b/rest_framework/static/rest_framework/css/bootstrap-tweaks.css @@ -10,6 +10,12 @@ a single block in the template. background: transparent; border-top-color: transparent; padding-top: 0; + text-align: right; +} + +#generic-content-form textarea { + font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace; + font-size: 80%; } .navbar-inverse .brand a { @@ -29,7 +35,7 @@ a single block in the template. z-index: 3; } -.navbar .navbar-inner { +.navbar { background: #2C2C2C; color: white; border: none; @@ -37,7 +43,7 @@ a single block in the template. border-radius: 0px; } -.navbar .navbar-inner .nav li, .navbar .navbar-inner .nav li a, .navbar .navbar-inner .brand:hover { +.navbar .nav li, .navbar .nav li a, .navbar .brand:hover { color: white; } @@ -45,11 +51,11 @@ a single block in the template. background: #2C2C2C; } -.navbar .navbar-inner .dropdown-menu li a, .navbar .navbar-inner .dropdown-menu li { +.navbar .dropdown-menu li a, .navbar .dropdown-menu li { color: #A30000; } -.navbar .navbar-inner .dropdown-menu li a:hover { +.navbar .dropdown-menu li a:hover { background: #EEEEEE; color: #C20000; } @@ -61,10 +67,10 @@ html { background: none; } -body, .navbar .navbar-inner .container-fluid { +/*body, .navbar .container-fluid { max-width: 1150px; margin: 0 auto; -} +}*/ body { background: url("../img/grid.png") repeat-x; diff --git a/rest_framework/templates/rest_framework/base.html b/rest_framework/templates/rest_framework/base.html index a84ccf26..2e03dd98 100644 --- a/rest_framework/templates/rest_framework/base.html +++ b/rest_framework/templates/rest_framework/base.html @@ -15,7 +15,8 @@ {% block style %} {% block bootstrap_theme %} - <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap.min.css" %}"/> + <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"> + <!--<link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap.min.css" %}"/>--> <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/bootstrap-tweaks.css" %}"/> {% endblock %} <link rel="stylesheet" type="text/css" href="{% static "rest_framework/css/prettify.css" %}"/> @@ -26,44 +27,42 @@ </head> {% block body %} - <body class="{% block bodyclass %}{% endblock %} container"> + <body class="{% block bodyclass %}{% endblock %}"> <div class="wrapper"> {% block navbar %} - <div class="navbar {% block bootstrap_navbar_variant %}navbar-inverse{% endblock %}"> - <div class="navbar-inner"> - <div class="container-fluid"> - <span> - {% block branding %} - <a class='brand' rel="nofollow" href='http://www.django-rest-framework.org'> - Django REST framework <span class="version">{{ version }}</span> - </a> - {% endblock %} - </span> - <ul class="nav pull-right"> - {% block userlinks %} - {% if user.is_authenticated %} - {% optional_logout request user %} - {% else %} - {% optional_login request %} - {% endif %} - {% endblock %} - </ul> - </div> + <div class="navbar navbar-static-top {% block bootstrap_navbar_variant %}navbar-inverse{% endblock %}"> + <div class="container"> + <span> + {% block branding %} + <a class='navbar-brand' rel="nofollow" href='http://www.django-rest-framework.org'> + Django REST framework <span class="version">{{ version }}</span> + </a> + {% endblock %} + </span> + <ul class="nav navbar-nav pull-right"> + {% block userlinks %} + {% if user.is_authenticated %} + {% optional_logout request user %} + {% else %} + {% optional_login request %} + {% endif %} + {% endblock %} + </ul> </div> </div> {% endblock %} + <div class="container"> {% block breadcrumbs %} <ul class="breadcrumb"> {% for breadcrumb_name, breadcrumb_url in breadcrumblist %} - <li> - <a href="{{ breadcrumb_url }}" {% if forloop.last %}class="active"{% endif %}> - {{ breadcrumb_name }} - </a> - {% if not forloop.last %}<span class="divider">›</span>{% endif %} - </li> + {% if forloop.last %} + <li class="active">{{ breadcrumb_name }}</li> + {% else %} + <li><a href="{{ breadcrumb_url }}">{{ breadcrumb_name }}</a></li> + {% endif %} {% endfor %} </ul> {% endblock %} @@ -238,6 +237,7 @@ {% endif %} </div> <!-- END Content --> + </div><!-- /.container --> <footer> {% block footer %} diff --git a/rest_framework/templates/rest_framework/fields/horizontal/checkbox.html b/rest_framework/templates/rest_framework/fields/horizontal/checkbox.html index dce4a5cf..dd3c3cef 100644 --- a/rest_framework/templates/rest_framework/fields/horizontal/checkbox.html +++ b/rest_framework/templates/rest_framework/fields/horizontal/checkbox.html @@ -2,7 +2,7 @@ <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 %}> + <input type="checkbox" name="{{ field.field_name }}" value="true" {% if field.value %}checked{% endif %}> {% if field.label %}{{ field.label }}{% endif %} </label> </div> diff --git a/rest_framework/templates/rest_framework/fields/horizontal/fieldset.html b/rest_framework/templates/rest_framework/fields/horizontal/fieldset.html index 86417633..843a56b2 100644 --- a/rest_framework/templates/rest_framework/fields/horizontal/fieldset.html +++ b/rest_framework/templates/rest_framework/fields/horizontal/fieldset.html @@ -4,7 +4,7 @@ <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() %} + {% for field_item in field.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 index 310154bb..6f1a504b 100644 --- a/rest_framework/templates/rest_framework/fields/horizontal/input.html +++ b/rest_framework/templates/rest_framework/fields/horizontal/input.html @@ -1,7 +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 %}> + <input type="{{ input_type }}" class="form-control" {% include "rest_framework/fields/attrs.html" %} {% if field.value %}value="{{ field.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/select.html b/rest_framework/templates/rest_framework/fields/horizontal/select.html index 3f8cab0a..7367d726 100644 --- a/rest_framework/templates/rest_framework/fields/horizontal/select.html +++ b/rest_framework/templates/rest_framework/fields/horizontal/select.html @@ -3,7 +3,7 @@ <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> + <option value="{{ key }}" {% if key == field.value %}selected{% endif %}>{{ text }}</option> {% endfor %} </select> </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 index 659eede8..381cda2c 100644 --- a/rest_framework/templates/rest_framework/fields/horizontal/select_checkbox.html +++ b/rest_framework/templates/rest_framework/fields/horizontal/select_checkbox.html @@ -4,7 +4,7 @@ {% 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 %}> + <input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in field.value %}checked{% endif %}> {{ text }} </label> {% endfor %} @@ -12,7 +12,7 @@ {% 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 %}> + <input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in field.value %}checked{% endif %}> {{ text }} </label> </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 index da25eb2b..29ba8661 100644 --- a/rest_framework/templates/rest_framework/fields/horizontal/select_multiple.html +++ b/rest_framework/templates/rest_framework/fields/horizontal/select_multiple.html @@ -3,7 +3,7 @@ <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> + <option value="{{ key }}" {% if key in field.value %}selected{% endif %}>{{ text }}</option> {% endfor %} </select> </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 index 188f05e2..20aab8b2 100644 --- a/rest_framework/templates/rest_framework/fields/horizontal/select_radio.html +++ b/rest_framework/templates/rest_framework/fields/horizontal/select_radio.html @@ -4,7 +4,7 @@ {% 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 %}> + <input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == field.value %}checked{% endif %}> {{ text }} </label> {% endfor %} @@ -12,7 +12,7 @@ {% 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 %}> + <input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == field.value %}checked{% endif %}> {{ text }} </label> </div> diff --git a/rest_framework/templates/rest_framework/fields/horizontal/textarea.html b/rest_framework/templates/rest_framework/fields/horizontal/textarea.html index e99266f3..3d016195 100644 --- a/rest_framework/templates/rest_framework/fields/horizontal/textarea.html +++ b/rest_framework/templates/rest_framework/fields/horizontal/textarea.html @@ -1,7 +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> + <textarea class="form-control" {% include "rest_framework/fields/attrs.html" %}>{% if field.value %}{{ field.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 index 01d30aae..289bbb4d 100644 --- a/rest_framework/templates/rest_framework/fields/inline/checkbox.html +++ b/rest_framework/templates/rest_framework/fields/inline/checkbox.html @@ -1,6 +1,6 @@ <div class="checkbox"> <label> - <input type="checkbox" name="{{ field.field_name }}" value="true" {% if value %}checked{% endif %}> + <input type="checkbox" name="{{ field.field_name }}" value="true" {% if field.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 index d22982fd..380d4627 100644 --- a/rest_framework/templates/rest_framework/fields/inline/fieldset.html +++ b/rest_framework/templates/rest_framework/fields/inline/fieldset.html @@ -1,3 +1,3 @@ -{% for field_item in value.field_items.values() %} +{% for field_item in field.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 index aefd1672..e4a92ccd 100644 --- a/rest_framework/templates/rest_framework/fields/inline/input.html +++ b/rest_framework/templates/rest_framework/fields/inline/input.html @@ -1,4 +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 %}> + <input type="{{ input_type }}" class="form-control" {% include "rest_framework/fields/attrs.html" %} {% if field.value %}value="{{ field.value }}"{% endif %}> </div> diff --git a/rest_framework/templates/rest_framework/fields/inline/select.html b/rest_framework/templates/rest_framework/fields/inline/select.html index cb9a7013..9f361c4a 100644 --- a/rest_framework/templates/rest_framework/fields/inline/select.html +++ b/rest_framework/templates/rest_framework/fields/inline/select.html @@ -2,7 +2,7 @@ {% 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> + <option value="{{ key }}" {% if key == field.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 index 424df93e..0f33fb69 100644 --- a/rest_framework/templates/rest_framework/fields/inline/select_checkbox.html +++ b/rest_framework/templates/rest_framework/fields/inline/select_checkbox.html @@ -3,7 +3,7 @@ {% 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 %}> + <input type="checkbox" name="{{ rest_framework/field.field_name }}" value="{{ key }}" {% if key in field.value %}checked{% endif %}> {{ text }} </label> </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 index 6fdfd672..7c9e5168 100644 --- a/rest_framework/templates/rest_framework/fields/inline/select_multiple.html +++ b/rest_framework/templates/rest_framework/fields/inline/select_multiple.html @@ -2,7 +2,7 @@ {% 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> + <option value="{{ key }}" {% if key in field.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 index ddabc9e9..177c0eeb 100644 --- a/rest_framework/templates/rest_framework/fields/inline/select_radio.html +++ b/rest_framework/templates/rest_framework/fields/inline/select_radio.html @@ -3,7 +3,7 @@ {% 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 %}> + <input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == field.value %}checked{% endif %}> {{ text }} </label> </div> diff --git a/rest_framework/templates/rest_framework/fields/inline/textarea.html b/rest_framework/templates/rest_framework/fields/inline/textarea.html index 31366809..8259487b 100644 --- a/rest_framework/templates/rest_framework/fields/inline/textarea.html +++ b/rest_framework/templates/rest_framework/fields/inline/textarea.html @@ -1,4 +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> + <textarea class="form-control" {% include "rest_framework/fields/attrs.html" %}>{% if field.value %}{{ field.value }}{% endif %}</textarea> </div> diff --git a/rest_framework/templates/rest_framework/fields/vertical/fieldset.html b/rest_framework/templates/rest_framework/fields/vertical/fieldset.html index cad32df9..8708916b 100644 --- a/rest_framework/templates/rest_framework/fields/vertical/fieldset.html +++ b/rest_framework/templates/rest_framework/fields/vertical/fieldset.html @@ -1,6 +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() %} + {% for field_item in field.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 index c25407d1..3ee2716a 100644 --- a/rest_framework/templates/rest_framework/fields/vertical/input.html +++ b/rest_framework/templates/rest_framework/fields/vertical/input.html @@ -1,5 +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 %}> + <input type="{{ input_type }}" class="form-control" {% include "rest_framework/fields/attrs.html" %} {% if field.value %}value="{{ field.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/select.html b/rest_framework/templates/rest_framework/fields/vertical/select.html index 44679d8a..dcc9a3cd 100644 --- a/rest_framework/templates/rest_framework/fields/vertical/select.html +++ b/rest_framework/templates/rest_framework/fields/vertical/select.html @@ -2,7 +2,7 @@ {% 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> + <option value="{{ key }}" {% if key == field.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 index e60574c0..1fbe6a94 100644 --- a/rest_framework/templates/rest_framework/fields/vertical/select_checkbox.html +++ b/rest_framework/templates/rest_framework/fields/vertical/select_checkbox.html @@ -4,7 +4,7 @@ <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 %}> + <input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in field.value %}checked{% endif %}> {{ text }} </label> {% endfor %} @@ -13,7 +13,7 @@ {% 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 %}> + <input type="checkbox" name="{{ field.field_name }}" value="{{ key }}" {% if key in field.value %}checked{% endif %}> {{ text }} </label> </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 index 00b25b4b..2cc40d99 100644 --- a/rest_framework/templates/rest_framework/fields/vertical/select_multiple.html +++ b/rest_framework/templates/rest_framework/fields/vertical/select_multiple.html @@ -2,7 +2,7 @@ {% 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> + <option value="{{ key }}" {% if key in field.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 index 4ffe38ea..470bcb0b 100644 --- a/rest_framework/templates/rest_framework/fields/vertical/select_radio.html +++ b/rest_framework/templates/rest_framework/fields/vertical/select_radio.html @@ -4,7 +4,7 @@ <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 %}> + <input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == field.value %}checked{% endif %}> {{ text }} </label> {% endfor %} @@ -13,7 +13,7 @@ {% 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 %}> + <input type="radio" name="{{ field.field_name }}" value="{{ key }}" {% if key == field.value %}checked{% endif %}> {{ text }} </label> </div> diff --git a/rest_framework/templates/rest_framework/fields/vertical/textarea.html b/rest_framework/templates/rest_framework/fields/vertical/textarea.html index 33cb27c7..406cfa77 100644 --- a/rest_framework/templates/rest_framework/fields/vertical/textarea.html +++ b/rest_framework/templates/rest_framework/fields/vertical/textarea.html @@ -1,5 +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> + <textarea class="form-control" {% include "rest_framework/fields/attrs.html" %}>{% if field.value %}{{ field.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 658aa293..162c5633 100644 --- a/rest_framework/templates/rest_framework/form.html +++ b/rest_framework/templates/rest_framework/form.html @@ -1,4 +1,4 @@ -<html> +<!-- <html> <head> <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"> </head> @@ -6,13 +6,15 @@ <div class="container"> <h1>User update</h1> -<div class="well"> +<div class="well"> --> {% load rest_framework %} <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 %} + {% for field in form %} + {% if not field.read_only %} + {% render_field field layout=layout renderer=renderer %} + {% endif %} {% endfor %} <!-- form.non_field_errors --> {% if layout == "horizontal" %} @@ -25,7 +27,7 @@ <button type="submit" class="btn btn-default">Submit</button> {% endif %} </form> - +<!-- </div> </div></body> -</html> +</html> --> diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py index 88ff9d4e..49a4c338 100644 --- a/rest_framework/templatetags/rest_framework.py +++ b/rest_framework/templatetags/rest_framework.py @@ -31,12 +31,9 @@ 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) +def render_field(field, layout=None, renderer=None): + return renderer.render_field(field, layout) @register.simple_tag diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index b4d33e39..30fae370 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -21,7 +21,14 @@ class ClassLookupDict(object): self.mapping = mapping def __getitem__(self, key): - for cls in inspect.getmro(key.__class__): + if hasattr(key, '_proxy_class'): + # Deal with proxy classes. Ie. BoundField behaves as if it + # is a Field instance when using ClassLookupDict. + base_class = key._proxy_class + else: + base_class = key.__class__ + + for cls in inspect.getmro(base_class): if cls in self.mapping: return self.mapping[cls] raise KeyError('Class %s not found in lookup.', cls.__name__) |
