From c69f960066dfdef2163a53205f27c2b9e457068f Mon Sep 17 00:00:00 2001 From: Pablo Recio Date: Sat, 18 May 2013 16:30:40 +0200 Subject: [PATCH 1/5] Adding a class attribute into JSONRenderer for ensuring ascii, and using it consistently --- rest_framework/renderers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 8361cd409..d55a3e0ea 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -49,6 +49,7 @@ class JSONRenderer(BaseRenderer): media_type = 'application/json' format = 'json' encoder_class = encoders.JSONEncoder + ensure_ascii = True def render(self, data, accepted_media_type=None, renderer_context=None): """ @@ -72,7 +73,7 @@ class JSONRenderer(BaseRenderer): except (ValueError, TypeError): indent = None - return json.dumps(data, cls=self.encoder_class, indent=indent) + return json.dumps(data, cls=self.encoder_class, indent=indent, ensure_ascii=self.ensure_ascii) class JSONPRenderer(JSONRenderer): From 97f034e3d65068f7bd1e982e6fd251222a4feea1 Mon Sep 17 00:00:00 2001 From: Pablo Recio Date: Sat, 18 May 2013 16:31:12 +0200 Subject: [PATCH 2/5] Adds UnicodeJSONRenderer which doesn't ensure ascii --- rest_framework/renderers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index d55a3e0ea..12e1107fa 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -76,6 +76,10 @@ class JSONRenderer(BaseRenderer): return json.dumps(data, cls=self.encoder_class, indent=indent, ensure_ascii=self.ensure_ascii) +class UnicodeJSONRenderer(JSONRenderer): + ensure_ascii = False + + class JSONPRenderer(JSONRenderer): """ Renderer which serializes to json, From 6dbbbc16da740fb27f9a5a390fb61400e9f6ff64 Mon Sep 17 00:00:00 2001 From: Pablo Recio Date: Sat, 18 May 2013 16:32:53 +0200 Subject: [PATCH 3/5] Better checking if the content can be printable in the BrowsableAPI --- rest_framework/renderers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 12e1107fa..4345a313b 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -325,7 +325,7 @@ class BrowsableAPIRenderer(BaseRenderer): renderer_context['indent'] = 4 content = renderer.render(data, accepted_media_type, renderer_context) - if not all(char in string.printable for char in content): + if not isinstance(content, six.text_type): return '[%d bytes of binary content]' return content From 71e29644a2950d8a82cb26f6a3e39fb76faf9707 Mon Sep 17 00:00:00 2001 From: Pablo Recio Date: Sat, 18 May 2013 16:50:09 +0200 Subject: [PATCH 4/5] Adds new renderer into the documentation --- docs/api-guide/renderers.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index b9a9fd7a3..1661ceecf 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -67,7 +67,7 @@ If your API includes views that can serve both regular webpages and API response ## JSONRenderer -Renders the request data into `JSON`. +Renders the request data into `JSON` enforcing ASCII encoding The client may additionally include an `'indent'` media type parameter, in which case the returned `JSON` will be indented. For example `Accept: application/json; indent=4`. @@ -75,6 +75,10 @@ The client may additionally include an `'indent'` media type parameter, in which **.format**: `'.json'` +## UnicodeJSONRenderer + +Same as `JSONRenderer` but doesn't enforce ASCII encoding + ## JSONPRenderer Renders the request data into `JSONP`. The `JSONP` media type provides a mechanism of allowing cross-domain AJAX requests, by wrapping a `JSON` response in a javascript callback. From b9b22976125fffa4552da695183bf75fbaf0b927 Mon Sep 17 00:00:00 2001 From: Pablo Recio Date: Sat, 18 May 2013 17:06:25 +0200 Subject: [PATCH 5/5] Tests proper encoding in JSONRenderer and UnicodeJSONRenderer --- rest_framework/tests/renderers.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/rest_framework/tests/renderers.py b/rest_framework/tests/renderers.py index 40bac9cb3..739f91841 100644 --- a/rest_framework/tests/renderers.py +++ b/rest_framework/tests/renderers.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from decimal import Decimal from django.core.cache import cache from django.test import TestCase @@ -8,7 +9,7 @@ from rest_framework.compat import yaml, etree, patterns, url, include from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \ - XMLRenderer, JSONPRenderer, BrowsableAPIRenderer + XMLRenderer, JSONPRenderer, BrowsableAPIRenderer, UnicodeJSONRenderer from rest_framework.parsers import YAMLParser, XMLParser from rest_framework.settings import api_settings from rest_framework.compat import StringIO @@ -254,6 +255,23 @@ class JSONRendererTests(TestCase): content = renderer.render(obj, 'application/json; indent=2') self.assertEqual(strip_trailing_whitespace(content), _indented_repr) + def test_check_ascii(self): + obj = {'countries': ['United Kingdom', 'France', 'España']} + renderer = JSONRenderer() + content = renderer.render(obj, 'application/json') + self.assertEqual(content, '{"countries": ["United Kingdom", "France", "Espa\\u00f1a"]}') + + +class UnicodeJSONRendererTests(TestCase): + """ + Tests specific for the Unicode JSON Renderer + """ + def test_proper_encoding(self): + obj = {'countries': ['United Kingdom', 'France', 'España']} + renderer = UnicodeJSONRenderer() + content = renderer.render(obj, 'application/json') + self.assertEqual(content, '{"countries": ["United Kingdom", "France", "España"]}') + class JSONPRendererTests(TestCase): """