diff options
Diffstat (limited to 'rest_framework')
33 files changed, 223 insertions, 150 deletions
diff --git a/rest_framework/fields.py b/rest_framework/fields.py index bba8ccae..0963d4bf 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -106,7 +106,7 @@ class Field(object):          'null': _('This field may not be null.')      }      default_validators = [] -    default_empty_html = None +    default_empty_html = empty      initial = None      def __init__(self, read_only=False, write_only=False, @@ -375,7 +375,6 @@ class NullBooleanField(Field):      default_error_messages = {          'invalid': _('`{input}` is not a valid boolean.')      } -    default_empty_html = None      initial = None      TRUE_VALUES = set(('t', 'T', 'true', 'True', 'TRUE', '1', 1, True))      FALSE_VALUES = set(('f', 'F', 'false', 'False', 'FALSE', '0', 0, 0.0, False)) @@ -411,7 +410,6 @@ class CharField(Field):      default_error_messages = {          'blank': _('This field may not be blank.')      } -    default_empty_html = ''      initial = ''      def __init__(self, **kwargs): @@ -689,10 +687,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) @@ -852,6 +850,7 @@ class MultipleChoiceField(ChoiceField):          'invalid_choice': _('`{input}` is not a valid choice.'),          'not_a_list': _('Expected a list of items but got type `{input_type}`')      } +    default_empty_html = []      def to_internal_value(self, data):          if isinstance(data, type('')) or not hasattr(data, '__iter__'): diff --git a/rest_framework/relations.py b/rest_framework/relations.py index dc9781e7..f8cd735d 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,14 @@ class ManyRelation(Field):      You shouldn't need to be using this class directly yourself.      """ +    initial = [] +    default_empty_html = []      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..21cb7ea2 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,19 @@ 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() +                 if field.get_value(self._initial_data) is not empty +             ], 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 +335,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 +349,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 +362,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 +371,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 +395,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 +407,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..6a37cae2 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; @@ -167,7 +173,7 @@ footer a:hover {  .page-header {    border-bottom: none;    padding-bottom: 0px; -  margin-bottom: 20px; +  margin: 0;  }  /* custom general page styles */ diff --git a/rest_framework/static/rest_framework/css/default.css b/rest_framework/static/rest_framework/css/default.css index 461cdfe5..82c6033b 100644 --- a/rest_framework/static/rest_framework/css/default.css +++ b/rest_framework/static/rest_framework/css/default.css @@ -33,7 +33,7 @@ h2, h3 {  }  ul.breadcrumb { -  margin: 80px 0 0 0; +  margin: 70px 0 0 0;  }  form select, form input, form textarea { @@ -67,5 +67,4 @@ pre {  .page-header {    border-bottom: none;    padding-bottom: 0px; -  margin-bottom: 20px;  } 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__)  | 
