mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-23 01:57:00 +03:00
Merge branch 'master' into html-form-renderer
This commit is contained in:
commit
c77e4a2c59
|
@ -88,7 +88,7 @@ The client may additionally include an `'indent'` media type parameter, in which
|
||||||
|
|
||||||
**.format**: `'.json'`
|
**.format**: `'.json'`
|
||||||
|
|
||||||
**.charset**: `utf-8`
|
**.charset**: `None`
|
||||||
|
|
||||||
## UnicodeJSONRenderer
|
## UnicodeJSONRenderer
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ Both the `JSONRenderer` and `UnicodeJSONRenderer` styles conform to [RFC 4627][r
|
||||||
|
|
||||||
**.format**: `'.json'`
|
**.format**: `'.json'`
|
||||||
|
|
||||||
**.charset**: `utf-8`
|
**.charset**: `None`
|
||||||
|
|
||||||
## JSONPRenderer
|
## JSONPRenderer
|
||||||
|
|
||||||
|
@ -295,12 +295,15 @@ By default renderer classes are assumed to be using the `UTF-8` encoding. To us
|
||||||
|
|
||||||
Note that if a renderer class returns a unicode string, then the response content will be coerced into a bytestring by the `Response` class, with the `charset` attribute set on the renderer used to determine the encoding.
|
Note that if a renderer class returns a unicode string, then the response content will be coerced into a bytestring by the `Response` class, with the `charset` attribute set on the renderer used to determine the encoding.
|
||||||
|
|
||||||
If the renderer returns a bytestring representing raw binary content, you should set a charset value of `None`, which will ensure the `Content-Type` header of the response will not have a `charset` value set. Doing so will also ensure that the browsable API will not attempt to display the binary content as a string.
|
If the renderer returns a bytestring representing raw binary content, you should set a charset value of `None`, which will ensure the `Content-Type` header of the response will not have a `charset` value set.
|
||||||
|
|
||||||
|
In some cases you may also want to set the `render_style` attribute to `'binary'`. Doing so will also ensure that the browsable API will not attempt to display the binary content as a string.
|
||||||
|
|
||||||
class JPEGRenderer(renderers.BaseRenderer):
|
class JPEGRenderer(renderers.BaseRenderer):
|
||||||
media_type = 'image/jpeg'
|
media_type = 'image/jpeg'
|
||||||
format = 'jpg'
|
format = 'jpg'
|
||||||
charset = None
|
charset = None
|
||||||
|
render_style = 'binary'
|
||||||
|
|
||||||
def render(self, data, media_type=None, renderer_context=None):
|
def render(self, data, media_type=None, renderer_context=None):
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -36,6 +36,7 @@ class BaseRenderer(object):
|
||||||
media_type = None
|
media_type = None
|
||||||
format = None
|
format = None
|
||||||
charset = 'utf-8'
|
charset = 'utf-8'
|
||||||
|
render_style = 'text'
|
||||||
|
|
||||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||||
raise NotImplemented('Renderer class requires .render() to be implemented')
|
raise NotImplemented('Renderer class requires .render() to be implemented')
|
||||||
|
@ -51,16 +52,17 @@ class JSONRenderer(BaseRenderer):
|
||||||
format = 'json'
|
format = 'json'
|
||||||
encoder_class = encoders.JSONEncoder
|
encoder_class = encoders.JSONEncoder
|
||||||
ensure_ascii = True
|
ensure_ascii = True
|
||||||
charset = 'utf-8'
|
charset = None
|
||||||
# Note that JSON encodings must be utf-8, utf-16 or utf-32.
|
# 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
|
# See: http://www.ietf.org/rfc/rfc4627.txt
|
||||||
|
# Also: http://lucumr.pocoo.org/2013/7/19/application-mimetypes-and-encodings/
|
||||||
|
|
||||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||||
"""
|
"""
|
||||||
Render `data` into JSON.
|
Render `data` into JSON.
|
||||||
"""
|
"""
|
||||||
if data is None:
|
if data is None:
|
||||||
return ''
|
return bytes()
|
||||||
|
|
||||||
# If 'indent' is provided in the context, then pretty print the result.
|
# If 'indent' is provided in the context, then pretty print the result.
|
||||||
# E.g. If we're being called by the BrowsableAPIRenderer.
|
# E.g. If we're being called by the BrowsableAPIRenderer.
|
||||||
|
@ -85,13 +87,12 @@ class JSONRenderer(BaseRenderer):
|
||||||
# and may (or may not) be unicode.
|
# and may (or may not) be unicode.
|
||||||
# On python 3.x json.dumps() returns unicode strings.
|
# On python 3.x json.dumps() returns unicode strings.
|
||||||
if isinstance(ret, six.text_type):
|
if isinstance(ret, six.text_type):
|
||||||
return bytes(ret.encode(self.charset))
|
return bytes(ret.encode('utf-8'))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class UnicodeJSONRenderer(JSONRenderer):
|
class UnicodeJSONRenderer(JSONRenderer):
|
||||||
ensure_ascii = False
|
ensure_ascii = False
|
||||||
charset = 'utf-8'
|
|
||||||
"""
|
"""
|
||||||
Renderer which serializes to JSON.
|
Renderer which serializes to JSON.
|
||||||
Does *not* apply JSON's character escaping for non-ascii characters.
|
Does *not* apply JSON's character escaping for non-ascii characters.
|
||||||
|
@ -108,6 +109,7 @@ class JSONPRenderer(JSONRenderer):
|
||||||
format = 'jsonp'
|
format = 'jsonp'
|
||||||
callback_parameter = 'callback'
|
callback_parameter = 'callback'
|
||||||
default_callback = 'callback'
|
default_callback = 'callback'
|
||||||
|
charset = 'utf-8'
|
||||||
|
|
||||||
def get_callback(self, renderer_context):
|
def get_callback(self, renderer_context):
|
||||||
"""
|
"""
|
||||||
|
@ -414,7 +416,10 @@ class BrowsableAPIRenderer(BaseRenderer):
|
||||||
renderer_context['indent'] = 4
|
renderer_context['indent'] = 4
|
||||||
content = renderer.render(data, accepted_media_type, renderer_context)
|
content = renderer.render(data, accepted_media_type, renderer_context)
|
||||||
|
|
||||||
if renderer.charset is None:
|
render_style = getattr(renderer, 'render_style', 'text')
|
||||||
|
assert render_style in ['text', 'binary'], 'Expected .render_style ' \
|
||||||
|
'"text" or "binary", but got "%s"' % render_style
|
||||||
|
if render_style == 'binary':
|
||||||
return '[%d bytes of binary content]' % len(content)
|
return '[%d bytes of binary content]' % len(content)
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
|
@ -189,7 +189,11 @@ class SimpleRouter(BaseRouter):
|
||||||
Given a viewset, return the portion of URL regex that is used
|
Given a viewset, return the portion of URL regex that is used
|
||||||
to match against a single instance.
|
to match against a single instance.
|
||||||
"""
|
"""
|
||||||
base_regex = '(?P<{lookup_field}>[^/]+)'
|
if self.trailing_slash:
|
||||||
|
base_regex = '(?P<{lookup_field}>[^/]+)'
|
||||||
|
else:
|
||||||
|
# Don't consume `.json` style suffixes
|
||||||
|
base_regex = '(?P<{lookup_field}>[^/.]+)'
|
||||||
lookup_field = getattr(viewset, 'lookup_field', 'pk')
|
lookup_field = getattr(viewset, 'lookup_field', 'pk')
|
||||||
return base_regex.format(lookup_field=lookup_field)
|
return base_regex.format(lookup_field=lookup_field)
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ class TestTrailingSlashRemoved(TestCase):
|
||||||
self.urls = self.router.urls
|
self.urls = self.router.urls
|
||||||
|
|
||||||
def test_urls_can_have_trailing_slash_removed(self):
|
def test_urls_can_have_trailing_slash_removed(self):
|
||||||
expected = ['^notes$', '^notes/(?P<pk>[^/]+)$']
|
expected = ['^notes$', '^notes/(?P<pk>[^/.]+)$']
|
||||||
for idx in range(len(expected)):
|
for idx in range(len(expected)):
|
||||||
self.assertEqual(expected[idx], self.urls[idx].regex.pattern)
|
self.assertEqual(expected[idx], self.urls[idx].regex.pattern)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user