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.
This commit is contained in:
Filip Wasilewski 2014-01-15 17:30:58 +01:00
parent e9fda70b4a
commit 352be6b557
3 changed files with 23 additions and 1 deletions

View File

@ -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.

View File

@ -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

View File

@ -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):
"""