diff options
| author | Tom Christie | 2012-09-20 17:44:34 +0100 |
|---|---|---|
| committer | Tom Christie | 2012-09-20 17:44:34 +0100 |
| commit | d9cba6398e2323b8d8cd34f791442528517e01b4 (patch) | |
| tree | 4a8d378584e10c669acee2574fbd47f38f35785f /rest_framework | |
| parent | f4670c89969503919cd597529f19174e67acd388 (diff) | |
| download | django-rest-framework-d9cba6398e2323b8d8cd34f791442528517e01b4.tar.bz2 | |
Clean up bits of templates etc
Diffstat (limited to 'rest_framework')
| -rw-r--r-- | rest_framework/renderers.py | 130 | ||||
| -rw-r--r-- | rest_framework/response.py | 2 | ||||
| -rw-r--r-- | rest_framework/serializers.py | 6 | ||||
| -rw-r--r-- | rest_framework/settings.py | 5 | ||||
| -rw-r--r-- | rest_framework/static/rest_framework/css/default.css (renamed from rest_framework/static/rest_framework/css/style.css) | 0 | ||||
| -rw-r--r-- | rest_framework/static/rest_framework/js/default.js | 5 | ||||
| -rw-r--r-- | rest_framework/templates/rest_framework/api.txt | 8 | ||||
| -rw-r--r-- | rest_framework/templates/rest_framework/base.html | 64 | ||||
| -rw-r--r-- | rest_framework/templatetags/rest_framework.py | 22 | ||||
| -rw-r--r-- | rest_framework/tests/renderers.py | 3 | ||||
| -rw-r--r-- | rest_framework/throttling.py | 2 | ||||
| -rw-r--r-- | rest_framework/views.py | 9 |
12 files changed, 99 insertions, 157 deletions
diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index dd9228d8..58bd11f0 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -5,10 +5,10 @@ Django REST framework also provides HTML and PlainText renderers that help self- by serializing the output along with documentation regarding the View, output status and headers, and providing forms and links depending on the allowed methods, renderers and parsers on the View. """ +import string from django import forms from django.template import RequestContext, loader from django.utils import simplejson as json - from rest_framework.compat import yaml from rest_framework.settings import api_settings from rest_framework.utils import dict2xml @@ -16,9 +16,7 @@ from rest_framework.utils import encoders from rest_framework.utils.breadcrumbs import get_breadcrumbs from rest_framework.utils.mediatypes import get_media_type_params, add_media_type_param, media_type_matches from rest_framework import VERSION -from rest_framework.fields import FloatField, IntegerField, DateTimeField, DateField, EmailField, CharField, BooleanField - -import string +from rest_framework import serializers class BaseRenderer(object): @@ -27,8 +25,6 @@ class BaseRenderer(object): and override the :meth:`render` method. """ - _FORMAT_QUERY_PARAM = 'format' - media_type = None format = None @@ -72,7 +68,7 @@ class BaseRenderer(object): class JSONRenderer(BaseRenderer): """ - Renderer which serializes to JSON + Renderer which serializes to json. """ media_type = 'application/json' @@ -81,7 +77,7 @@ class JSONRenderer(BaseRenderer): def render(self, obj=None, media_type=None): """ - Renders *obj* into serialized JSON. + Render `obj` into json. """ if obj is None: return '' @@ -96,28 +92,37 @@ class JSONRenderer(BaseRenderer): except (ValueError, TypeError): indent = None - return json.dumps(obj, cls=self.encoder_class, indent=indent, sort_keys=sort_keys) + return json.dumps(obj, cls=self.encoder_class, + indent=indent, sort_keys=sort_keys) class JSONPRenderer(JSONRenderer): """ - Renderer which serializes to JSONP + Renderer which serializes to json, + wrapping the json output in a callback function. """ media_type = 'application/javascript' format = 'jsonp' - renderer_class = JSONRenderer callback_parameter = 'callback' + default_callback = 'callback' - def _get_callback(self): - return self.view.request.GET.get(self.callback_parameter, self.callback_parameter) - - def _get_renderer(self): - return self.renderer_class(self.view) + def get_callback(self): + """ + Determine the name of the callback to wrap around the json output. + """ + params = self.view.request.GET + return params.get(self.callback_parameter, self.default_callback) def render(self, obj=None, media_type=None): - callback = self._get_callback() - json = self._get_renderer().render(obj, media_type) + """ + Renders into jsonp, wrapping the json output in a callback function. + + Clients may set the callback function name using a query parameter + on the URL, for example: ?callback=exampleCallbackName + """ + callback = self.get_callback() + json = super(JSONPRenderer, self).render(obj, media_type) return "%s(%s);" % (callback, json) @@ -180,13 +185,13 @@ class TemplateRenderer(BaseRenderer): return template.render(context) -class DocumentingTemplateRenderer(BaseRenderer): +class DocumentingHTMLRenderer(BaseRenderer): """ - Base class for renderers used to self-document the API. - Implementing classes should extend this class and set the template attribute. + HTML renderer used to self-document the API. """ - - template = None + media_type = 'text/html' + format = 'html' + template = 'rest_framework/api.html' def _get_content(self, view, request, obj, media_type): """ @@ -198,7 +203,7 @@ class DocumentingTemplateRenderer(BaseRenderer): # Find the first valid renderer and render the content. (Don't use another documenting renderer.) renderers = [renderer for renderer in view.renderer_classes - if not issubclass(renderer, DocumentingTemplateRenderer)] + if not issubclass(renderer, DocumentingHTMLRenderer)] if not renderers: return '[No renderers were found]' @@ -219,13 +224,13 @@ class DocumentingTemplateRenderer(BaseRenderer): return # We need to map our Fields to Django's Fields. field_mapping = dict([ - [FloatField.__name__, forms.FloatField], - [IntegerField.__name__, forms.IntegerField], - [DateTimeField.__name__, forms.DateTimeField], - [DateField.__name__, forms.DateField], - [EmailField.__name__, forms.EmailField], - [CharField.__name__, forms.CharField], - [BooleanField.__name__, forms.BooleanField] + [serializers.FloatField.__name__, forms.FloatField], + [serializers.IntegerField.__name__, forms.IntegerField], + [serializers.DateTimeField.__name__, forms.DateTimeField], + [serializers.DateField.__name__, forms.DateField], + [serializers.EmailField.__name__, forms.EmailField], + [serializers.CharField.__name__, forms.CharField], + [serializers.BooleanField.__name__, forms.BooleanField] ]) # Creating an on the fly form see: http://stackoverflow.com/questions/3915024/dynamically-creating-classes-python @@ -299,8 +304,11 @@ class DocumentingTemplateRenderer(BaseRenderer): The context used in the template contains all the information needed to self-document the response to this request. """ + view = self.view + request = view.request + response = view.response - content = self._get_content(self.view, self.view.request, obj, media_type) + content = self._get_content(view, request, obj, media_type) put_form_instance = self._get_form_instance(self.view, 'put') post_form_instance = self._get_form_instance(self.view, 'post') @@ -313,9 +321,9 @@ class DocumentingTemplateRenderer(BaseRenderer): template = loader.get_template(self.template) context = RequestContext(self.view.request, { 'content': content, - 'view': self.view, - 'request': self.view.request, - 'response': self.view.response, + 'view': view, + 'request': request, + 'response': response, 'description': description, 'name': name, 'version': VERSION, @@ -324,8 +332,6 @@ class DocumentingTemplateRenderer(BaseRenderer): 'available_formats': [renderer.format for renderer in self.view.renderer_classes], 'put_form': put_form_instance, 'post_form': post_form_instance, - 'FORMAT_PARAM': self._FORMAT_QUERY_PARAM, - 'METHOD_PARAM': getattr(self.view, '_METHOD_PARAM', None), 'api_settings': api_settings }) @@ -338,53 +344,3 @@ class DocumentingTemplateRenderer(BaseRenderer): self.view.response.status_code = 200 return ret - - -class DocumentingHTMLRenderer(DocumentingTemplateRenderer): - """ - Renderer which provides a browsable HTML interface for an API. - See the examples at http://api.django-rest-framework.org to see this in action. - """ - - media_type = 'text/html' - format = 'html' - template = 'rest_framework/api.html' - - -class DocumentingXHTMLRenderer(DocumentingTemplateRenderer): - """ - Identical to DocumentingHTMLRenderer, except with an xhtml media type. - We need this to be listed in preference to xml in order to return HTML to WebKit based browsers, - given their Accept headers. - """ - - media_type = 'application/xhtml+xml' - format = 'xhtml' - template = 'rest_framework/api.html' - - -class DocumentingPlainTextRenderer(DocumentingTemplateRenderer): - """ - Renderer that serializes the object with the default renderer, but also provides plain-text - documentation of the returned status and headers, and of the resource's name and description. - Useful for browsing an API with command line tools. - """ - - media_type = 'text/plain' - format = 'txt' - template = 'rest_framework/api.txt' - - -DEFAULT_RENDERERS = ( - JSONRenderer, - JSONPRenderer, - DocumentingHTMLRenderer, - DocumentingXHTMLRenderer, - DocumentingPlainTextRenderer, - XMLRenderer -) - -if yaml: - DEFAULT_RENDERERS += (YAMLRenderer, ) -else: - YAMLRenderer = None diff --git a/rest_framework/response.py b/rest_framework/response.py index 29034e25..61e677a5 100644 --- a/rest_framework/response.py +++ b/rest_framework/response.py @@ -1,5 +1,5 @@ -from django.template.response import SimpleTemplateResponse from django.core.handlers.wsgi import STATUS_CODE_TEXT +from django.template.response import SimpleTemplateResponse class Response(SimpleTemplateResponse): diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index afc9f511..96e46d94 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -1,9 +1,9 @@ -from decimal import Decimal -from django.core.serializers.base import DeserializedObject -from django.utils.datastructures import SortedDict import copy import datetime import types +from decimal import Decimal +from django.core.serializers.base import DeserializedObject +from django.utils.datastructures import SortedDict from rest_framework.fields import * diff --git a/rest_framework/settings.py b/rest_framework/settings.py index fef8097e..a0b99010 100644 --- a/rest_framework/settings.py +++ b/rest_framework/settings.py @@ -24,9 +24,7 @@ from django.utils import importlib DEFAULTS = { 'DEFAULT_RENDERERS': ( 'rest_framework.renderers.JSONRenderer', - 'rest_framework.renderers.JSONPRenderer', 'rest_framework.renderers.DocumentingHTMLRenderer', - 'rest_framework.renderers.DocumentingPlainTextRenderer', ), 'DEFAULT_PARSERS': ( 'rest_framework.parsers.JSONParser', @@ -38,7 +36,8 @@ DEFAULTS = { ), 'DEFAULT_PERMISSIONS': (), 'DEFAULT_THROTTLES': (), - 'DEFAULT_CONTENT_NEGOTIATION': 'rest_framework.negotiation.DefaultContentNegotiation', + 'DEFAULT_CONTENT_NEGOTIATION': + 'rest_framework.negotiation.DefaultContentNegotiation', 'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser', 'UNAUTHENTICATED_TOKEN': None, diff --git a/rest_framework/static/rest_framework/css/style.css b/rest_framework/static/rest_framework/css/default.css index cfd41460..cfd41460 100644 --- a/rest_framework/static/rest_framework/css/style.css +++ b/rest_framework/static/rest_framework/css/default.css diff --git a/rest_framework/static/rest_framework/js/default.js b/rest_framework/static/rest_framework/js/default.js new file mode 100644 index 00000000..ecaccc0f --- /dev/null +++ b/rest_framework/static/rest_framework/js/default.js @@ -0,0 +1,5 @@ +prettyPrint(); + +$('.js-tooltip').tooltip({ + delay: 1000 +}); diff --git a/rest_framework/templates/rest_framework/api.txt b/rest_framework/templates/rest_framework/api.txt deleted file mode 100644 index c87a154c..00000000 --- a/rest_framework/templates/rest_framework/api.txt +++ /dev/null @@ -1,8 +0,0 @@ -{% autoescape off %}{{ name }} - -{{ description }} - -HTTP {{ response.status_code }} {{ response.status_text }} -{% for key, val in response.headers.items %}{{ key }}: {{ val }} -{% endfor %} -{{ content }}{% endautoescape %} diff --git a/rest_framework/templates/rest_framework/base.html b/rest_framework/templates/rest_framework/base.html index 71fc5222..4b42778f 100644 --- a/rest_framework/templates/rest_framework/base.html +++ b/rest_framework/templates/rest_framework/base.html @@ -4,26 +4,28 @@ <!DOCTYPE html> <html> <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + {% block head %} - {% block bootstrap_theme %} - <link rel="stylesheet" type="text/css" href="{% get_static_prefix %}rest_framework/css/bootstrap.min.css"/> - <link rel="stylesheet" type="text/css" href="{% get_static_prefix %}rest_framework/css/bootstrap-tweaks.css"/> + {% block meta %} + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <meta name="robots" content="NONE,NOARCHIVE" /> {% endblock %} - <link rel="stylesheet" type="text/css" href='{% get_static_prefix %}rest_framework/css/prettify.css'/> - <link rel="stylesheet" type="text/css" href='{% get_static_prefix %}rest_framework/css/style.css'/> - {% block extrastyle %}{% endblock %} - <title>{% block title %}Django REST framework - {{ name }}{% endblock %}</title> + <title>{% block title %}Django REST framework{% endblock %}</title> - {% block extrahead %}{% endblock %} - - {% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %} + {% block style %} + <link rel="stylesheet" type="text/css" href="{% get_static_prefix %}rest_framework/css/bootstrap.min.css"/> + <link rel="stylesheet" type="text/css" href="{% get_static_prefix %}rest_framework/css/bootstrap-tweaks.css"/> + <link rel="stylesheet" type="text/css" href='{% get_static_prefix %}rest_framework/css/prettify.css'/> + <link rel="stylesheet" type="text/css" href='{% get_static_prefix %}rest_framework/css/default.css'/> + {% endblock %} + {% endblock %} </head> <body class="{% block bodyclass %}{% endblock %} container"> + {% block navbar %} <div class="navbar navbar-fixed-top {% block bootstrap_navbar_variant %}navbar-inverse{% endblock %}"> <div class="navbar-inner"> <div class="container"> @@ -32,31 +34,28 @@ </span> <ul class="nav pull-right"> {% block userlinks %} - {% if user.is_active %} + {% if user.is_authenticated %} <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown"> Welcome, {{ user }} <b class="caret"></b> </a> <ul class="dropdown-menu"> - <li>{% optional_logout %}</li> + <li>{% optional_logout request %}</li> </ul> </li> {% else %} - <li>{% optional_login %}</li> + <li>{% optional_login request %}</li> {% endif %} {% endblock %} </ul> </div> </div> </div> - - {% block global_heading %}{% endblock %} - + {% endblock %} {% 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 %} @@ -79,11 +78,9 @@ </button> <ul class="dropdown-menu"> {% for format in available_formats %} - {% with FORMAT_PARAM|add:"="|add:format as param %} - <li> - <a class="js-tooltip format-option" href='{{ request.get_full_path|add_query_param:param }}' rel="nofollow" title="Do a GET request on the {{ name }} resource with the format set to `{{ format }}`">{{ format }}</a> - </li> - {% endwith %} + <li> + <a class="js-tooltip format-option" href='{% add_query_param request api_settings.URL_FORMAT_OVERRIDE format %}' rel="nofollow" title="Do a GET request on the {{ name }} resource with the format set to `{{ format }}`">{{ format }}</a> + </li> {% endfor %} </ul> </div> @@ -188,24 +185,19 @@ </div> <!-- END Content --> + {% block footer %} <div id="footer"> - {% block footer %} - <a class="powered-by" href='http://django-rest-framework.org'>Django REST framework</a> <span class="version">{{ version }}</span> - {% endblock %} + <a class="powered-by" href='http://django-rest-framework.org'>Django REST framework</a> <span class="version">{{ version }}</span> </div> + {% endblock %} + </div> + + {% block script %} <script src="{% get_static_prefix %}rest_framework/js/jquery-1.8.1-min.js"></script> <script src="{% get_static_prefix %}rest_framework/js/bootstrap.min.js"></script> <script src="{% get_static_prefix %}rest_framework/js/prettify-min.js"></script> - <script> - prettyPrint(); - - $('.js-tooltip').tooltip({ - delay: 1000 - }); - </script> - - {% block extrabody %}{% endblock %} - + <script src="{% get_static_prefix %}rest_framework/js/default.js"></script> + {% endblock %} </body> </html> diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py index db71b0d3..bfc450ee 100644 --- a/rest_framework/templatetags/rest_framework.py +++ b/rest_framework/templatetags/rest_framework.py @@ -46,8 +46,8 @@ def replace_query_param(url, key, val): # And the template tags themselves... -@register.simple_tag(takes_context=True) -def optional_login(context): +@register.simple_tag +def optional_login(request): """ Include a login snippet if REST framework's login view is in the URLconf. """ @@ -56,13 +56,12 @@ def optional_login(context): except NoReverseMatch: return '' - request = context['request'] snippet = "<a href='%s?next=%s'>Log in</a>" % (login_url, request.path) return snippet -@register.simple_tag(takes_context=True) -def optional_logout(context): +@register.simple_tag +def optional_logout(request): """ Include a logout snippet if REST framework's logout view is in the URLconf. """ @@ -71,17 +70,16 @@ def optional_logout(context): except NoReverseMatch: return '' - request = context['request'] snippet = "<a href='%s?next=%s'>Log out</a>" % (logout_url, request.path) return snippet -@register.filter -def add_query_param(url, param): +@register.simple_tag +def add_query_param(request, key, val): """ + Add a query parameter to the current request url, and return the new url. """ - key, val = param.split('=') - return replace_query_param(url, key, val) + return replace_query_param(request.get_full_path(), key, val) @register.filter @@ -114,7 +112,7 @@ def add_class(value, css_class): return value -@register.filter(is_safe=True) +@register.filter def urlize_quoted_links(text, trim_url_limit=None, nofollow=True, autoescape=True): """ Converts any URLs in text into clickable links. @@ -170,4 +168,4 @@ def urlize_quoted_links(text, trim_url_limit=None, nofollow=True, autoescape=Tru words[i] = mark_safe(word) elif autoescape: words[i] = escape(word) - return u''.join(words) + return mark_safe(u''.join(words)) diff --git a/rest_framework/tests/renderers.py b/rest_framework/tests/renderers.py index 06954412..b7c386a3 100644 --- a/rest_framework/tests/renderers.py +++ b/rest_framework/tests/renderers.py @@ -4,6 +4,7 @@ from django.conf.urls.defaults import patterns, url, include from django.test import TestCase from rest_framework import status +from rest_framework.compat import yaml from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \ @@ -246,7 +247,7 @@ class JSONPRendererTests(TestCase): self.assertEquals(resp.content, '%s(%s);' % (callback_func, _flat_repr)) -if YAMLRenderer: +if yaml: _yaml_repr = 'foo: [bar, baz]\n' class YAMLRendererTests(TestCase): diff --git a/rest_framework/throttling.py b/rest_framework/throttling.py index b66284c3..e7750478 100644 --- a/rest_framework/throttling.py +++ b/rest_framework/throttling.py @@ -1,6 +1,6 @@ +import time from django.core.cache import cache from rest_framework.settings import api_settings -import time class BaseThrottle(object): diff --git a/rest_framework/views.py b/rest_framework/views.py index a9710110..2d7fbefb 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -11,12 +11,11 @@ from django.http import Http404 from django.utils.html import escape from django.utils.safestring import mark_safe from django.views.decorators.csrf import csrf_exempt - -from rest_framework.compat import View as _View, apply_markdown +from rest_framework import status, exceptions +from rest_framework.compat import View, apply_markdown from rest_framework.response import Response from rest_framework.request import Request from rest_framework.settings import api_settings -from rest_framework import status, exceptions def _remove_trailing_string(content, trailing): @@ -53,7 +52,7 @@ def _camelcase_to_spaces(content): return re.sub(camelcase_boundry, ' \\1', content).strip() -class APIView(_View): +class APIView(View): settings = api_settings renderer_classes = api_settings.DEFAULT_RENDERERS @@ -86,7 +85,7 @@ class APIView(_View): def default_response_headers(self): return { 'Allow': ', '.join(self.allowed_methods), - 'Vary': 'Authenticate, Accept' + 'Vary': 'Accept' } def get_name(self): |
