mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-06-22 14:33:31 +03:00
UNICODE_JSON and COMPACT_JSON settings
This commit is contained in:
parent
250755def7
commit
5e39e159ee
|
@ -137,6 +137,16 @@ class Field(object):
|
||||||
messages.update(error_messages or {})
|
messages.update(error_messages or {})
|
||||||
self.error_messages = messages
|
self.error_messages = messages
|
||||||
|
|
||||||
|
def __new__(cls, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
When a field is instantiated, we store the arguments that were used,
|
||||||
|
so that we can present a helpful representation of the object.
|
||||||
|
"""
|
||||||
|
instance = super(Field, cls).__new__(cls)
|
||||||
|
instance._args = args
|
||||||
|
instance._kwargs = kwargs
|
||||||
|
return instance
|
||||||
|
|
||||||
def bind(self, field_name, parent, root):
|
def bind(self, field_name, parent, root):
|
||||||
"""
|
"""
|
||||||
Setup the context for the field instance.
|
Setup the context for the field instance.
|
||||||
|
@ -249,16 +259,6 @@ class Field(object):
|
||||||
raise AssertionError(msg)
|
raise AssertionError(msg)
|
||||||
raise ValidationError(msg.format(**kwargs))
|
raise ValidationError(msg.format(**kwargs))
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
When a field is instantiated, we store the arguments that were used,
|
|
||||||
so that we can present a helpful representation of the object.
|
|
||||||
"""
|
|
||||||
instance = super(Field, cls).__new__(cls)
|
|
||||||
instance._args = args
|
|
||||||
instance._kwargs = kwargs
|
|
||||||
return instance
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return representation.field_repr(self)
|
return representation.field_repr(self)
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ class JSONParser(BaseParser):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
media_type = 'application/json'
|
media_type = 'application/json'
|
||||||
renderer_class = renderers.UnicodeJSONRenderer
|
renderer_class = renderers.JSONRenderer
|
||||||
|
|
||||||
def parse(self, stream, media_type=None, parser_context=None):
|
def parse(self, stream, media_type=None, parser_context=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -26,6 +26,10 @@ from rest_framework.utils.breadcrumbs import get_breadcrumbs
|
||||||
from rest_framework import exceptions, status, VERSION
|
from rest_framework import exceptions, status, VERSION
|
||||||
|
|
||||||
|
|
||||||
|
def zero_as_none(value):
|
||||||
|
return None if value == 0 else value
|
||||||
|
|
||||||
|
|
||||||
class BaseRenderer(object):
|
class BaseRenderer(object):
|
||||||
"""
|
"""
|
||||||
All renderers should extend this class, setting the `media_type`
|
All renderers should extend this class, setting the `media_type`
|
||||||
|
@ -44,13 +48,13 @@ class BaseRenderer(object):
|
||||||
class JSONRenderer(BaseRenderer):
|
class JSONRenderer(BaseRenderer):
|
||||||
"""
|
"""
|
||||||
Renderer which serializes to JSON.
|
Renderer which serializes to JSON.
|
||||||
Applies JSON's backslash-u character escaping for non-ascii characters.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
media_type = 'application/json'
|
media_type = 'application/json'
|
||||||
format = 'json'
|
format = 'json'
|
||||||
encoder_class = encoders.JSONEncoder
|
encoder_class = encoders.JSONEncoder
|
||||||
ensure_ascii = True
|
ensure_ascii = not api_settings.UNICODE_JSON
|
||||||
|
compact = api_settings.COMPACT_JSON
|
||||||
|
|
||||||
# We don't set a charset because JSON is a binary encoding,
|
# We don't set a charset because JSON is a binary encoding,
|
||||||
# that can be encoded as utf-8, utf-16 or utf-32.
|
# that can be encoded as utf-8, utf-16 or utf-32.
|
||||||
|
@ -62,9 +66,10 @@ class JSONRenderer(BaseRenderer):
|
||||||
if accepted_media_type:
|
if accepted_media_type:
|
||||||
# If the media type looks like 'application/json; indent=4',
|
# If the media type looks like 'application/json; indent=4',
|
||||||
# then pretty print the result.
|
# then pretty print the result.
|
||||||
|
# Note that we coerce `indent=0` into `indent=None`.
|
||||||
base_media_type, params = parse_header(accepted_media_type.encode('ascii'))
|
base_media_type, params = parse_header(accepted_media_type.encode('ascii'))
|
||||||
try:
|
try:
|
||||||
return max(min(int(params['indent']), 8), 0)
|
return zero_as_none(max(min(int(params['indent']), 8), 0))
|
||||||
except (KeyError, ValueError, TypeError):
|
except (KeyError, ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -81,10 +86,12 @@ class JSONRenderer(BaseRenderer):
|
||||||
|
|
||||||
renderer_context = renderer_context or {}
|
renderer_context = renderer_context or {}
|
||||||
indent = self.get_indent(accepted_media_type, renderer_context)
|
indent = self.get_indent(accepted_media_type, renderer_context)
|
||||||
|
separators = (',', ':') if (indent is None and self.compact) else (', ', ': ')
|
||||||
|
|
||||||
ret = json.dumps(
|
ret = json.dumps(
|
||||||
data, cls=self.encoder_class,
|
data, cls=self.encoder_class,
|
||||||
indent=indent, ensure_ascii=self.ensure_ascii
|
indent=indent, ensure_ascii=self.ensure_ascii,
|
||||||
|
separators=separators
|
||||||
)
|
)
|
||||||
|
|
||||||
# On python 2.x json.dumps() returns bytestrings if ensure_ascii=True,
|
# On python 2.x json.dumps() returns bytestrings if ensure_ascii=True,
|
||||||
|
@ -96,14 +103,6 @@ class JSONRenderer(BaseRenderer):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class UnicodeJSONRenderer(JSONRenderer):
|
|
||||||
ensure_ascii = False
|
|
||||||
"""
|
|
||||||
Renderer which serializes to JSON.
|
|
||||||
Does *not* apply JSON's character escaping for non-ascii characters.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class JSONPRenderer(JSONRenderer):
|
class JSONPRenderer(JSONRenderer):
|
||||||
"""
|
"""
|
||||||
Renderer which serializes to json,
|
Renderer which serializes to json,
|
||||||
|
@ -196,7 +195,7 @@ class YAMLRenderer(BaseRenderer):
|
||||||
format = 'yaml'
|
format = 'yaml'
|
||||||
encoder = encoders.SafeDumper
|
encoder = encoders.SafeDumper
|
||||||
charset = 'utf-8'
|
charset = 'utf-8'
|
||||||
ensure_ascii = True
|
ensure_ascii = False
|
||||||
|
|
||||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||||
"""
|
"""
|
||||||
|
@ -210,14 +209,6 @@ class YAMLRenderer(BaseRenderer):
|
||||||
return yaml.dump(data, stream=None, encoding=self.charset, Dumper=self.encoder, allow_unicode=not self.ensure_ascii)
|
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):
|
class TemplateHTMLRenderer(BaseRenderer):
|
||||||
"""
|
"""
|
||||||
An HTML renderer for use with templates.
|
An HTML renderer for use with templates.
|
||||||
|
|
|
@ -112,6 +112,9 @@ DEFAULTS = {
|
||||||
),
|
),
|
||||||
'TIME_FORMAT': None,
|
'TIME_FORMAT': None,
|
||||||
|
|
||||||
|
# Encoding
|
||||||
|
'UNICODE_JSON': True,
|
||||||
|
'COMPACT_JSON': True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ from rest_framework.compat import yaml, etree, StringIO
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \
|
from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \
|
||||||
XMLRenderer, JSONPRenderer, BrowsableAPIRenderer, UnicodeJSONRenderer, UnicodeYAMLRenderer
|
XMLRenderer, JSONPRenderer, BrowsableAPIRenderer
|
||||||
from rest_framework.parsers import YAMLParser, XMLParser
|
from rest_framework.parsers import YAMLParser, XMLParser
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framework.test import APIRequestFactory
|
from rest_framework.test import APIRequestFactory
|
||||||
|
@ -32,7 +32,7 @@ RENDERER_B_SERIALIZER = lambda x: ('Renderer B: %s' % x).encode('ascii')
|
||||||
|
|
||||||
|
|
||||||
expected_results = [
|
expected_results = [
|
||||||
((elem for elem in [1, 2, 3]), JSONRenderer, b'[1, 2, 3]') # Generator
|
((elem for elem in [1, 2, 3]), JSONRenderer, b'[1,2,3]') # Generator
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ class RendererEndToEndTests(TestCase):
|
||||||
self.assertNotContains(resp, '>text/html; charset=utf-8<')
|
self.assertNotContains(resp, '>text/html; charset=utf-8<')
|
||||||
|
|
||||||
|
|
||||||
_flat_repr = '{"foo": ["bar", "baz"]}'
|
_flat_repr = '{"foo":["bar","baz"]}'
|
||||||
_indented_repr = '{\n "foo": [\n "bar",\n "baz"\n ]\n}'
|
_indented_repr = '{\n "foo": [\n "bar",\n "baz"\n ]\n}'
|
||||||
|
|
||||||
|
|
||||||
|
@ -373,12 +373,6 @@ class JSONRendererTests(TestCase):
|
||||||
content = renderer.render(obj, 'application/json; indent=2')
|
content = renderer.render(obj, 'application/json; indent=2')
|
||||||
self.assertEqual(strip_trailing_whitespace(content.decode('utf-8')), _indented_repr)
|
self.assertEqual(strip_trailing_whitespace(content.decode('utf-8')), _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"]}'.encode('utf-8'))
|
|
||||||
|
|
||||||
|
|
||||||
class UnicodeJSONRendererTests(TestCase):
|
class UnicodeJSONRendererTests(TestCase):
|
||||||
"""
|
"""
|
||||||
|
@ -386,9 +380,22 @@ class UnicodeJSONRendererTests(TestCase):
|
||||||
"""
|
"""
|
||||||
def test_proper_encoding(self):
|
def test_proper_encoding(self):
|
||||||
obj = {'countries': ['United Kingdom', 'France', 'España']}
|
obj = {'countries': ['United Kingdom', 'France', 'España']}
|
||||||
renderer = UnicodeJSONRenderer()
|
renderer = JSONRenderer()
|
||||||
content = renderer.render(obj, 'application/json')
|
content = renderer.render(obj, 'application/json')
|
||||||
self.assertEqual(content, '{"countries": ["United Kingdom", "France", "España"]}'.encode('utf-8'))
|
self.assertEqual(content, '{"countries":["United Kingdom","France","España"]}'.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
|
class AsciiJSONRendererTests(TestCase):
|
||||||
|
"""
|
||||||
|
Tests specific for the Unicode JSON Renderer
|
||||||
|
"""
|
||||||
|
def test_proper_encoding(self):
|
||||||
|
class AsciiJSONRenderer(JSONRenderer):
|
||||||
|
ensure_ascii = True
|
||||||
|
obj = {'countries': ['United Kingdom', 'France', 'España']}
|
||||||
|
renderer = AsciiJSONRenderer()
|
||||||
|
content = renderer.render(obj, 'application/json')
|
||||||
|
self.assertEqual(content, '{"countries":["United Kingdom","France","Espa\\u00f1a"]}'.encode('utf-8'))
|
||||||
|
|
||||||
|
|
||||||
class JSONPRendererTests(TestCase):
|
class JSONPRendererTests(TestCase):
|
||||||
|
@ -487,13 +494,9 @@ if yaml:
|
||||||
def assertYAMLContains(self, content, string):
|
def assertYAMLContains(self, content, string):
|
||||||
self.assertTrue(string in content, '%r not in %r' % (string, content))
|
self.assertTrue(string in content, '%r not in %r' % (string, content))
|
||||||
|
|
||||||
class UnicodeYAMLRendererTests(TestCase):
|
|
||||||
"""
|
|
||||||
Tests specific for the Unicode YAML Renderer
|
|
||||||
"""
|
|
||||||
def test_proper_encoding(self):
|
def test_proper_encoding(self):
|
||||||
obj = {'countries': ['United Kingdom', 'France', 'España']}
|
obj = {'countries': ['United Kingdom', 'France', 'España']}
|
||||||
renderer = UnicodeYAMLRenderer()
|
renderer = YAMLRenderer()
|
||||||
content = renderer.render(obj, 'application/yaml')
|
content = renderer.render(obj, 'application/yaml')
|
||||||
self.assertEqual(content.strip(), 'countries: [United Kingdom, France, España]'.encode('utf-8'))
|
self.assertEqual(content.strip(), 'countries: [United Kingdom, France, España]'.encode('utf-8'))
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ class TestMaxValueValidatorValidation(TestCase):
|
||||||
request = factory.patch('/{0}'.format(obj.pk), {'number_value': 101}, format='json')
|
request = factory.patch('/{0}'.format(obj.pk), {'number_value': 101}, format='json')
|
||||||
view = UpdateMaxValueValidationModel().as_view()
|
view = UpdateMaxValueValidationModel().as_view()
|
||||||
response = view(request, pk=obj.pk).render()
|
response = view(request, pk=obj.pk).render()
|
||||||
self.assertEqual(response.content, b'{"number_value": ["Ensure this value is less than or equal to 100."]}')
|
self.assertEqual(response.content, b'{"number_value":["Ensure this value is less than or equal to 100."]}')
|
||||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user