From 352be6b5570c2cf038ab1afab1ef62608b071399 Mon Sep 17 00:00:00 2001 From: Filip Wasilewski Date: Wed, 15 Jan 2014 17:30:58 +0100 Subject: [PATCH] Allow to specify JSON separators for rendering The json.dumps function takes an optional `separators` param that controls the JSON item_separator and dict_separator strings. Setting the separators to `(',', ':')` makes the renderer to produce the most compact encoding. --- docs/api-guide/renderers.md | 2 ++ rest_framework/renderers.py | 8 +++++++- rest_framework/tests/test_renderers.py | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md index 7798827bc..2a6f492b0 100644 --- a/docs/api-guide/renderers.md +++ b/docs/api-guide/renderers.md @@ -90,6 +90,8 @@ The client may additionally include an `'indent'` media type parameter, in which **.charset**: `None` +**.separators**: `None` + ## UnicodeJSONRenderer Renders the request data into `JSON`, using utf-8 encoding. diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 2fdd33376..5c22ecad1 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -54,6 +54,7 @@ class JSONRenderer(BaseRenderer): encoder_class = encoders.JSONEncoder ensure_ascii = True charset = None + separators = None # 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/ @@ -69,6 +70,7 @@ class JSONRenderer(BaseRenderer): # E.g. If we're being called by the BrowsableAPIRenderer. renderer_context = renderer_context or {} indent = renderer_context.get('indent', None) + separators = renderer_context.get('separators', self.separators) if accepted_media_type: # If the media type looks like 'application/json; indent=4', @@ -79,9 +81,11 @@ class JSONRenderer(BaseRenderer): indent = max(min(int(indent), 8), 0) except (ValueError, TypeError): indent = None + if indent: + separators = None ret = json.dumps(data, cls=self.encoder_class, - indent=indent, ensure_ascii=self.ensure_ascii) + indent=indent, separators=separators, 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, @@ -385,6 +389,7 @@ class BrowsableAPIRenderer(BaseRenderer): return '[No renderers were found]' renderer_context['indent'] = 4 + renderer_context['separators'] = None content = renderer.render(data, accepted_media_type, renderer_context) render_style = getattr(renderer, 'render_style', 'text') @@ -488,6 +493,7 @@ class BrowsableAPIRenderer(BaseRenderer): accepted = self.accepted_media_type context = self.renderer_context.copy() context['indent'] = 4 + context['separators'] = None content = renderer.render(serializer.data, accepted, context) else: content = None diff --git a/rest_framework/tests/test_renderers.py b/rest_framework/tests/test_renderers.py index 2ae8ae18c..6038f66ad 100644 --- a/rest_framework/tests/test_renderers.py +++ b/rest_framework/tests/test_renderers.py @@ -339,6 +339,20 @@ class JSONRendererTests(TestCase): content = renderer.render(obj, 'application/json') self.assertEqual(content, '{"countries": ["United Kingdom", "France", "Espa\\u00f1a"]}'.encode('utf-8')) + def test_separators(self): + obj = {'countries': ['United Kingdom', 'France', 'España']} + class CompactJSONRenderer(JSONRenderer): + separators = (',', ':') + renderer = CompactJSONRenderer() + content = renderer.render(obj, 'application/json') + self.assertEqual(content, '{"countries":["United Kingdom","France","Espa\\u00f1a"]}'.encode('utf-8')) + + def test_separators_context(self): + obj = {'countries': ['United Kingdom', 'France', 'España']} + renderer = JSONRenderer() + content = renderer.render(obj, 'application/json', renderer_context={'separators': (',', ':')}) + self.assertEqual(content, '{"countries":["United Kingdom","France","Espa\\u00f1a"]}'.encode('utf-8')) + class UnicodeJSONRendererTests(TestCase): """