diff options
| author | Tom Christie | 2014-10-15 15:13:28 +0100 | 
|---|---|---|
| committer | Tom Christie | 2014-10-15 15:13:28 +0100 | 
| commit | b4f3379c7002f0c80a26605fdd9c69d7cef2f16f (patch) | |
| tree | 2a4939cc2c46c9fdfab4284ec29aa9be8925d710 /rest_framework | |
| parent | e8ea365c15b13185efc2ba03e57a3302f783d538 (diff) | |
| download | django-rest-framework-b4f3379c7002f0c80a26605fdd9c69d7cef2f16f.tar.bz2 | |
Support fields that reference a simple callable
Diffstat (limited to 'rest_framework')
| -rw-r--r-- | rest_framework/fields.py | 4 | ||||
| -rw-r--r-- | rest_framework/renderers.py | 105 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 4 | ||||
| -rw-r--r-- | rest_framework/static/rest_framework/css/bootstrap-tweaks.css | 4 | ||||
| -rw-r--r-- | rest_framework/static/rest_framework/css/default.css | 4 | ||||
| -rw-r--r-- | rest_framework/templatetags/rest_framework.py | 7 | 
6 files changed, 78 insertions, 50 deletions
| diff --git a/rest_framework/fields.py b/rest_framework/fields.py index b881ad13..24dfaaf5 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -66,6 +66,8 @@ def get_attribute(instance, attrs):                  return instance[attr]              except (KeyError, TypeError, AttributeError):                  raise exc +    if is_simple_callable(instance): +        return instance()      return instance @@ -1025,8 +1027,6 @@ class ReadOnlyField(Field):          super(ReadOnlyField, self).__init__(**kwargs)      def to_representation(self, value): -        if is_simple_callable(value): -            return value()          return value diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 5fae75f2..d5defa31 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -340,76 +340,101 @@ class HTMLFormRenderer(BaseRenderer):      media_type = 'text/html'      format = 'form'      charset = 'utf-8' +    template_pack = 'rest_framework/horizontal/' +    base_template = 'form.html' -    field_templates = ClassLookupDict({ +    default_style = ClassLookupDict({          serializers.Field: { -            'default': 'input.html' +            'base_template': 'input.html', +            'input_type': 'text'          }, -        serializers.BooleanField: { -            'default': 'checkbox.html' +        serializers.EmailField: { +            'base_template': 'input.html', +            'input_type': 'email' +        }, +        serializers.URLField: { +            'base_template': 'input.html', +            'input_type': 'url' +        }, +        serializers.IntegerField: { +            'base_template': 'input.html', +            'input_type': 'number' +        }, +        serializers.DateTimeField: { +            'base_template': 'input.html', +            'input_type': 'datetime-local'          }, -        serializers.CharField: { -            'default': 'input.html', -            'textarea': 'textarea.html' +        serializers.DateField: { +            'base_template': 'input.html', +            'input_type': 'date' +        }, +        serializers.TimeField: { +            'base_template': 'input.html', +            'input_type': 'time' +        }, +        serializers.BooleanField: { +            'base_template': 'checkbox.html'          },          serializers.ChoiceField: { -            'default': 'select.html', -            'radio': 'select_radio.html' +            'base_template': 'select.html',  # Also valid: 'radio.html'          },          serializers.MultipleChoiceField: { -            'default': 'select_multiple.html', -            'checkbox': 'select_checkbox.html' +            'base_template': 'select_multiple.html',  # Also valid: 'checkbox_multiple.html'          },          serializers.ManyRelation: { -            'default': 'select_multiple.html', -            'checkbox': 'select_checkbox.html' +            'base_template': 'select_multiple.html',  # Also valid: 'checkbox_multiple.html'          },          serializers.Serializer: { -            'default': 'fieldset.html' +            'base_template': 'fieldset.html'          },          serializers.ListSerializer: { -            'default': 'list_fieldset.html' +            'base_template': 'list_fieldset.html'          }      }) -    input_type = ClassLookupDict({ -        serializers.Field: 'text', -        serializers.EmailField: 'email', -        serializers.URLField: 'url', -        serializers.IntegerField: 'number', -        serializers.DateTimeField: 'datetime-local', -        serializers.DateField: 'date', -        serializers.TimeField: 'time', -    }) +    def render_field(self, field, parent_style): +        style = dict(self.default_style[field]) +        style.update(field.style) +        if 'template_pack' not in style: +            style['template_pack'] = parent_style['template_pack'] +        style['renderer'] = self -    def render_field(self, field, template_pack=None): -        style_type = field.style.get('type', 'default') - -        input_type = self.input_type[field] -        if input_type == 'datetime-local' and isinstance(field.value, six.text_type): +        if style.get('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 = template_pack + '/fields/' + base +        if 'template' in style: +            template_name = style['template'] +        else: +            template_name = style['template_pack'].strip('/') + '/' + style['base_template'] +          template = loader.get_template(template_name) -        context = Context({ -            'field': field, -            'input_type': input_type, -            'renderer': self, -        }) +        context = Context({'field': field, 'style': style})          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.          """ +        form = data.serializer +        meta = getattr(form, 'Meta', None) +        style = getattr(meta, 'style', {}) +        if 'template_pack' not in style: +            style['template_pack'] = self.template_pack +        if 'base_template' not in style: +            style['base_template'] = self.base_template +        style['renderer'] = self + +        if 'template' in style: +            template_name = style['template'] +        else: +            template_name = style['template_pack'].strip('/') + '/' + style['base_template'] +          renderer_context = renderer_context or {}          request = renderer_context['request'] -        template = loader.get_template('rest_framework/horizontal/form.html') +        template = loader.get_template(template_name)          context = RequestContext(request, { -            'form': data.serializer, -            'template_pack': 'rest_framework/horizontal', -            'renderer': self +            'form': form, +            'style': style          })          return template.render(context) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index c844605f..534be6f9 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -115,7 +115,7 @@ class BaseSerializer(Field):      @property      def data(self):          if not hasattr(self, '_data'): -            if self.instance is not None: +            if self.instance is not None and not getattr(self, '_errors', None):                  self._data = self.to_representation(self.instance)              else:                  self._data = self.get_initial() @@ -339,7 +339,7 @@ class Serializer(BaseSerializer):          Dict of native values <- Dict of primitive datatypes.          """          ret = {} -        errors = {} +        errors = ReturnDict(serializer=self)          fields = [field for field in self.fields.values() if not field.read_only]          for field in fields: diff --git a/rest_framework/static/rest_framework/css/bootstrap-tweaks.css b/rest_framework/static/rest_framework/css/bootstrap-tweaks.css index 6a37cae2..36c7be48 100644 --- a/rest_framework/static/rest_framework/css/bootstrap-tweaks.css +++ b/rest_framework/static/rest_framework/css/bootstrap-tweaks.css @@ -115,10 +115,6 @@ html, body {    margin-bottom: 0;  } -.well form .help-block { -  color: #999999; -} -  .nav-tabs {    border: 0;  } diff --git a/rest_framework/static/rest_framework/css/default.css b/rest_framework/static/rest_framework/css/default.css index 82c6033b..4f52cc56 100644 --- a/rest_framework/static/rest_framework/css/default.css +++ b/rest_framework/static/rest_framework/css/default.css @@ -36,6 +36,10 @@ ul.breadcrumb {    margin: 70px 0 0 0;  } +.breadcrumb li.active a { +  color: #777; +} +  form select, form input, form textarea {    width: 90%;  } diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py index c092d39f..d9424f02 100644 --- a/rest_framework/templatetags/rest_framework.py +++ b/rest_framework/templatetags/rest_framework.py @@ -8,6 +8,7 @@ from django.utils.html import escape  from django.utils.safestring import SafeData, mark_safe  from django.utils.html import smart_urlquote  from rest_framework.compat import urlparse, force_text +from rest_framework.renderers import HTMLFormRenderer  import re  register = template.Library() @@ -32,8 +33,10 @@ class_re = re.compile(r'(?<=class=["\'])(.*)(?=["\'])')  # And the template tags themselves...  @register.simple_tag -def render_field(field, template_pack=None, renderer=None): -    return renderer.render_field(field, template_pack) +def render_field(field, style=None): +    style = style or {} +    renderer = style.get('renderer', HTMLFormRenderer()) +    return renderer.render_field(field, style)  @register.simple_tag | 
