diff options
| author | Tom Christie | 2011-05-10 12:21:48 +0100 |
|---|---|---|
| committer | Tom Christie | 2011-05-10 12:21:48 +0100 |
| commit | 527e4ffdf7f7798dc17757a26d8fd6b155a49bf9 (patch) | |
| tree | 8a7811d692c136e78dd3ad64a6219d30f501d194 /djangorestframework/renderers.py | |
| parent | 8f58ee489d34b200acfc2666816eb32e47c8cef5 (diff) | |
| download | django-rest-framework-527e4ffdf7f7798dc17757a26d8fd6b155a49bf9.tar.bz2 | |
renderer API work
Diffstat (limited to 'djangorestframework/renderers.py')
| -rw-r--r-- | djangorestframework/renderers.py | 129 |
1 files changed, 81 insertions, 48 deletions
diff --git a/djangorestframework/renderers.py b/djangorestframework/renderers.py index 78dc26b5..6c3d23e2 100644 --- a/djangorestframework/renderers.py +++ b/djangorestframework/renderers.py @@ -1,4 +1,5 @@ -"""Renderers are used to serialize a View's output into specific media types. +""" +Renderers are used to serialize a View's output into specific media types. django-rest-framework also provides HTML and PlainText renderers that help self-document the API, by serializing the output along with documentation regarding the Resource, output status and headers, and providing forms and links depending on the allowed methods, renderers and parsers on the Resource. @@ -7,64 +8,78 @@ from django import forms from django.conf import settings from django.template import RequestContext, loader from django.utils import simplejson as json -from django import forms -from djangorestframework.utils import dict2xml, url_resolves +from djangorestframework import status from djangorestframework.compat import apply_markdown +from djangorestframework.utils import dict2xml, url_resolves from djangorestframework.utils.breadcrumbs import get_breadcrumbs from djangorestframework.utils.description import get_name, get_description -from djangorestframework import status +from djangorestframework.utils.mediatypes import get_media_type_params, add_media_type_param -from urllib import quote_plus -import string -import re from decimal import Decimal +import re +import string +from urllib import quote_plus + +__all__ = ( + 'BaseRenderer', + 'JSONRenderer', + 'DocumentingHTMLRenderer', + 'DocumentingXHTMLRenderer', + 'DocumentingPlainTextRenderer', + 'XMLRenderer' +) -# TODO: Rename verbose to something more appropriate -# TODO: Maybe None could be handled more cleanly. It'd be nice if it was handled by default, -# and only have an renderer output anything if it explicitly provides support for that. class BaseRenderer(object): - """All renderers must extend this class, set the media_type attribute, and - override the render() function.""" + """ + All renderers must extend this class, set the media_type attribute, and + override the render() function. + """ media_type = None def __init__(self, view): self.view = view - def render(self, output=None, verbose=False): - """By default render simply returns the ouput as-is. - Override this method to provide for other behaviour.""" - if output is None: + def render(self, obj=None, media_type=None): + """ + By default render simply returns the ouput as-is. + Override this method to provide for other behavior. + """ + if obj is None: return '' - return output + return obj class TemplateRenderer(BaseRenderer): - """A Base class provided for convenience. + """ + A Base class provided for convenience. - Render the output simply by using the given template. + Render the object simply by using the given template. To create a template renderer, subclass this, and set - the ``media_type`` and ``template`` attributes""" + the ``media_type`` and ``template`` attributes + """ media_type = None template = None - def render(self, output=None, verbose=False): - if output is None: + def render(self, obj=None, media_type=None): + if obj is None: return '' - context = RequestContext(self.request, output) + context = RequestContext(self.request, obj) return self.template.render(context) class DocumentingTemplateRenderer(BaseRenderer): - """Base class for renderers used to self-document the API. - Implementing classes should extend this class and set the template attribute.""" + """ + Base class for renderers used to self-document the API. + Implementing classes should extend this class and set the template attribute. + """ template = None - def _get_content(self, resource, request, output): - """Get the content as if it had been renderted by a non-documenting renderer. + def _get_content(self, resource, request, obj, media_type): + """Get the content as if it had been rendered by a non-documenting renderer. (Typically this will be the content as it would have been if the Resource had been requested with an 'Accept: */*' header, although with verbose style formatting if appropriate.)""" @@ -73,8 +88,9 @@ class DocumentingTemplateRenderer(BaseRenderer): renderers = [renderer for renderer in resource.renderers if not isinstance(renderer, DocumentingTemplateRenderer)] if not renderers: return '[No renderers were found]' - - content = renderers[0](resource).render(output, verbose=True) + + media_type = add_media_type_param(media_type, 'indent', '4') + content = renderers[0](resource).render(obj, media_type) if not all(char in string.printable for char in content): return '[%d bytes of binary content]' @@ -149,8 +165,8 @@ class DocumentingTemplateRenderer(BaseRenderer): return GenericContentForm(resource) - def render(self, output=None): - content = self._get_content(self.view, self.view.request, output) + def render(self, obj=None, media_type=None): + content = self._get_content(self.view, self.view.request, obj, media_type) form_instance = self._get_form_instance(self.view) if url_resolves(settings.LOGIN_URL) and url_resolves(settings.LOGOUT_URL): @@ -194,46 +210,63 @@ class DocumentingTemplateRenderer(BaseRenderer): class JSONRenderer(BaseRenderer): - """Renderer which serializes to JSON""" + """ + Renderer which serializes to JSON + """ media_type = 'application/json' - def render(self, output=None, verbose=False): - if output is None: + def render(self, obj=None, media_type=None): + if obj is None: return '' - if verbose: - return json.dumps(output, indent=4, sort_keys=True) - return json.dumps(output) + + indent = get_media_type_params(media_type).get('indent', None) + if indent is not None: + try: + indent = int(indent) + except ValueError: + indent = None + + sort_keys = indent and True or False + return json.dumps(obj, indent=indent, sort_keys=sort_keys) class XMLRenderer(BaseRenderer): - """Renderer which serializes to XML.""" + """ + Renderer which serializes to XML. + """ media_type = 'application/xml' - def render(self, output=None, verbose=False): - if output is None: + def render(self, obj=None, media_type=None): + if obj is None: return '' - return dict2xml(output) + return dict2xml(obj) class DocumentingHTMLRenderer(DocumentingTemplateRenderer): - """Renderer which provides a browsable HTML interface for an API. - See the examples listed in the django-rest-framework documentation to see this in actions.""" + """ + 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' template = 'renderer.html' class DocumentingXHTMLRenderer(DocumentingTemplateRenderer): - """Identical to DocumentingHTMLRenderer, except with an xhtml media type. + """ + 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.""" + given their Accept headers. + """ media_type = 'application/xhtml+xml' template = 'renderer.html' class DocumentingPlainTextRenderer(DocumentingTemplateRenderer): - """Renderer that serializes the output with the default renderer, but also provides plain-text - doumentation of the returned status and headers, and of the resource's name and description. - Useful for browsing an API with command line tools.""" + """ + 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' template = 'renderer.txt' |
