diff options
Diffstat (limited to 'rest_framework/renderers.py')
| -rw-r--r-- | rest_framework/renderers.py | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 7a7da561..748ebac9 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -8,7 +8,6 @@ REST framework also provides an HTML renderer the renders the browsable API. """ from __future__ import unicode_literals -import copy import json import django from django import forms @@ -16,11 +15,9 @@ from django.core.exceptions import ImproperlyConfigured from django.http.multipartparser import parse_header from django.template import RequestContext, loader, Template from django.test.client import encode_multipart +from django.utils import six from django.utils.xmlutils import SimplerXMLGenerator -from rest_framework.compat import StringIO -from rest_framework.compat import six -from rest_framework.compat import smart_text -from rest_framework.compat import yaml +from rest_framework.compat import StringIO, smart_text, yaml from rest_framework.exceptions import ParseError from rest_framework.settings import api_settings from rest_framework.request import is_form_media_type, override_method @@ -54,35 +51,41 @@ class JSONRenderer(BaseRenderer): format = 'json' encoder_class = encoders.JSONEncoder ensure_ascii = True - charset = None - # JSON is a binary encoding, that can be encoded as utf-8, utf-16 or utf-32. + + # We don't set a charset because JSON is a binary encoding, + # that can be encoded as utf-8, utf-16 or utf-32. # See: http://www.ietf.org/rfc/rfc4627.txt # Also: http://lucumr.pocoo.org/2013/7/19/application-mimetypes-and-encodings/ + charset = None + + def get_indent(self, accepted_media_type, renderer_context): + if accepted_media_type: + # If the media type looks like 'application/json; indent=4', + # then pretty print the result. + base_media_type, params = parse_header(accepted_media_type.encode('ascii')) + try: + return max(min(int(params['indent']), 8), 0) + except (KeyError, ValueError, TypeError): + pass + + # If 'indent' is provided in the context, then pretty print the result. + # E.g. If we're being called by the BrowsableAPIRenderer. + return renderer_context.get('indent', None) def render(self, data, accepted_media_type=None, renderer_context=None): """ - Render `data` into JSON. + Render `data` into JSON, returning a bytestring. """ if data is None: return bytes() - # If 'indent' is provided in the context, then pretty print the result. - # E.g. If we're being called by the BrowsableAPIRenderer. renderer_context = renderer_context or {} - indent = renderer_context.get('indent', None) + indent = self.get_indent(accepted_media_type, renderer_context) - if accepted_media_type: - # If the media type looks like 'application/json; indent=4', - # then pretty print the result. - base_media_type, params = parse_header(accepted_media_type.encode('ascii')) - indent = params.get('indent', indent) - try: - indent = max(min(int(indent), 8), 0) - except (ValueError, TypeError): - indent = None - - ret = json.dumps(data, cls=self.encoder_class, - indent=indent, ensure_ascii=self.ensure_ascii) + ret = json.dumps( + data, cls=self.encoder_class, + indent=indent, ensure_ascii=self.ensure_ascii + ) # On python 2.x json.dumps() returns bytestrings if ensure_ascii=True, # but if ensure_ascii=False, the return type is underspecified, @@ -193,6 +196,7 @@ class YAMLRenderer(BaseRenderer): format = 'yaml' encoder = encoders.SafeDumper charset = 'utf-8' + ensure_ascii = True def render(self, data, accepted_media_type=None, renderer_context=None): """ @@ -203,7 +207,15 @@ class YAMLRenderer(BaseRenderer): if data is None: return '' - return yaml.dump(data, stream=None, encoding=self.charset, Dumper=self.encoder) + return yaml.dump(data, stream=None, encoding=self.charset, Dumper=self.encoder, allow_unicode=not self.ensure_ascii) + + +class UnicodeYAMLRenderer(YAMLRenderer): + """ + Renderer which serializes to YAML. + Does *not* apply character escaping for non-ascii characters. + """ + ensure_ascii = False class TemplateHTMLRenderer(BaseRenderer): @@ -400,7 +412,7 @@ class BrowsableAPIRenderer(BaseRenderer): """ Returns True if a form should be shown for this method. """ - if not method in view.allowed_methods: + if method not in view.allowed_methods: return # Not a valid method if not api_settings.FORM_METHOD_OVERRIDE: @@ -440,8 +452,10 @@ class BrowsableAPIRenderer(BaseRenderer): if method in ('DELETE', 'OPTIONS'): return True # Don't actually need to return a form - if (not getattr(view, 'get_serializer', None) - or not any(is_form_media_type(parser.media_type) for parser in view.parser_classes)): + if ( + not getattr(view, 'get_serializer', None) + or not any(is_form_media_type(parser.media_type) for parser in view.parser_classes) + ): return serializer = view.get_serializer(instance=obj, data=data, files=files) @@ -562,7 +576,7 @@ class BrowsableAPIRenderer(BaseRenderer): 'version': VERSION, 'breadcrumblist': self.get_breadcrumbs(request), 'allowed_methods': view.allowed_methods, - 'available_formats': [renderer.format for renderer in view.renderer_classes], + '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), @@ -611,4 +625,3 @@ class MultiPartRenderer(BaseRenderer): def render(self, data, accepted_media_type=None, renderer_context=None): return encode_multipart(self.BOUNDARY, data) - |
