mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-03-27 13:24:26 +03:00
Added proper charset support
This commit is contained in:
parent
5bebd29f11
commit
0d3d66cb02
|
@ -58,17 +58,11 @@ class DefaultContentNegotiation(BaseContentNegotiation):
|
||||||
_MediaType(media_type).precedence):
|
_MediaType(media_type).precedence):
|
||||||
# Eg client requests '*/*'
|
# Eg client requests '*/*'
|
||||||
# Accepted media type is 'application/json'
|
# Accepted media type is 'application/json'
|
||||||
renderer_and_media_type = renderer, renderer.media_type
|
return renderer, renderer.media_type
|
||||||
else:
|
else:
|
||||||
# Eg client requests 'application/json; indent=8'
|
# Eg client requests 'application/json; indent=8'
|
||||||
# Accepted media type is 'application/json; indent=8'
|
# Accepted media type is 'application/json; indent=8'
|
||||||
renderer_and_media_type = renderer, media_type
|
return renderer, media_type
|
||||||
if renderer.charset:
|
|
||||||
charset = renderer.charset
|
|
||||||
else:
|
|
||||||
charset = self.__class__.settings.DEFAULT_CHARSET
|
|
||||||
retval = renderer_and_media_type + (charset,)
|
|
||||||
return retval
|
|
||||||
|
|
||||||
raise exceptions.NotAcceptable(available_renderers=renderers)
|
raise exceptions.NotAcceptable(available_renderers=renderers)
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ class BaseRenderer(object):
|
||||||
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')
|
||||||
|
|
||||||
|
|
||||||
class JSONRenderer(BaseRenderer):
|
class JSONRenderer(BaseRenderer):
|
||||||
"""
|
"""
|
||||||
Renderer which serializes to json.
|
Renderer which serializes to json.
|
||||||
|
@ -115,6 +116,7 @@ class XMLRenderer(BaseRenderer):
|
||||||
|
|
||||||
media_type = 'application/xml'
|
media_type = 'application/xml'
|
||||||
format = 'xml'
|
format = 'xml'
|
||||||
|
charset = 'utf-8'
|
||||||
|
|
||||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||||
"""
|
"""
|
||||||
|
@ -164,6 +166,7 @@ class YAMLRenderer(BaseRenderer):
|
||||||
media_type = 'application/yaml'
|
media_type = 'application/yaml'
|
||||||
format = 'yaml'
|
format = 'yaml'
|
||||||
encoder = encoders.SafeDumper
|
encoder = encoders.SafeDumper
|
||||||
|
charset = 'utf-8'
|
||||||
|
|
||||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||||
"""
|
"""
|
||||||
|
@ -204,6 +207,7 @@ class TemplateHTMLRenderer(BaseRenderer):
|
||||||
'%(status_code)s.html',
|
'%(status_code)s.html',
|
||||||
'api_exception.html'
|
'api_exception.html'
|
||||||
]
|
]
|
||||||
|
charset = 'utf-8'
|
||||||
|
|
||||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||||
"""
|
"""
|
||||||
|
@ -275,6 +279,7 @@ class StaticHTMLRenderer(TemplateHTMLRenderer):
|
||||||
"""
|
"""
|
||||||
media_type = 'text/html'
|
media_type = 'text/html'
|
||||||
format = 'html'
|
format = 'html'
|
||||||
|
charset = 'utf-8'
|
||||||
|
|
||||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||||
renderer_context = renderer_context or {}
|
renderer_context = renderer_context or {}
|
||||||
|
@ -296,6 +301,7 @@ class BrowsableAPIRenderer(BaseRenderer):
|
||||||
media_type = 'text/html'
|
media_type = 'text/html'
|
||||||
format = 'api'
|
format = 'api'
|
||||||
template = 'rest_framework/api.html'
|
template = 'rest_framework/api.html'
|
||||||
|
charset = 'utf-8'
|
||||||
|
|
||||||
def get_default_renderer(self, view):
|
def get_default_renderer(self, view):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -18,7 +18,7 @@ class Response(SimpleTemplateResponse):
|
||||||
|
|
||||||
def __init__(self, data=None, status=200,
|
def __init__(self, data=None, status=200,
|
||||||
template_name=None, headers=None,
|
template_name=None, headers=None,
|
||||||
exception=False):
|
exception=False, charset=None):
|
||||||
"""
|
"""
|
||||||
Alters the init arguments slightly.
|
Alters the init arguments slightly.
|
||||||
For example, drop 'template_name', and instead use 'data'.
|
For example, drop 'template_name', and instead use 'data'.
|
||||||
|
@ -30,6 +30,7 @@ class Response(SimpleTemplateResponse):
|
||||||
self.data = data
|
self.data = data
|
||||||
self.template_name = template_name
|
self.template_name = template_name
|
||||||
self.exception = exception
|
self.exception = exception
|
||||||
|
self.charset = charset
|
||||||
|
|
||||||
if headers:
|
if headers:
|
||||||
for name, value in six.iteritems(headers):
|
for name, value in six.iteritems(headers):
|
||||||
|
@ -39,18 +40,21 @@ class Response(SimpleTemplateResponse):
|
||||||
def rendered_content(self):
|
def rendered_content(self):
|
||||||
renderer = getattr(self, 'accepted_renderer', None)
|
renderer = getattr(self, 'accepted_renderer', None)
|
||||||
media_type = getattr(self, 'accepted_media_type', None)
|
media_type = getattr(self, 'accepted_media_type', None)
|
||||||
charset = getattr(self, 'charset', None)
|
|
||||||
context = getattr(self, 'renderer_context', None)
|
context = getattr(self, 'renderer_context', None)
|
||||||
|
|
||||||
assert renderer, ".accepted_renderer not set on Response"
|
assert renderer, ".accepted_renderer not set on Response"
|
||||||
assert media_type, ".accepted_media_type not set on Response"
|
assert media_type, ".accepted_media_type not set on Response"
|
||||||
assert context, ".renderer_context not set on Response"
|
assert context, ".renderer_context not set on Response"
|
||||||
context['response'] = self
|
context['response'] = self
|
||||||
if charset is not None:
|
|
||||||
ct = "{0}; charset={1}".format(media_type, charset)
|
if self.charset is None:
|
||||||
|
self.charset = renderer.charset
|
||||||
|
|
||||||
|
if self.charset is not None:
|
||||||
|
content_type = "{0}; charset={1}".format(media_type, self.charset)
|
||||||
else:
|
else:
|
||||||
ct = media_type
|
content_type = media_type
|
||||||
self['Content-Type'] = ct
|
self['Content-Type'] = content_type
|
||||||
return renderer.render(self.data, media_type, context)
|
return renderer.render(self.data, media_type, context)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -71,4 +75,4 @@ class Response(SimpleTemplateResponse):
|
||||||
for key in ('accepted_renderer', 'renderer_context', 'data'):
|
for key in ('accepted_renderer', 'renderer_context', 'data'):
|
||||||
if key in state:
|
if key in state:
|
||||||
del state[key]
|
del state[key]
|
||||||
return state
|
return state
|
||||||
|
|
|
@ -83,8 +83,6 @@ DEFAULTS = {
|
||||||
'FORMAT_SUFFIX_KWARG': 'format',
|
'FORMAT_SUFFIX_KWARG': 'format',
|
||||||
|
|
||||||
# Input and output formats
|
# Input and output formats
|
||||||
'DEFAULT_CHARSET': None,
|
|
||||||
|
|
||||||
'DATE_INPUT_FORMATS': (
|
'DATE_INPUT_FORMATS': (
|
||||||
ISO_8601,
|
ISO_8601,
|
||||||
),
|
),
|
||||||
|
|
|
@ -66,19 +66,19 @@ class TemplateHTMLRendererTests(TestCase):
|
||||||
def test_simple_html_view(self):
|
def test_simple_html_view(self):
|
||||||
response = self.client.get('/')
|
response = self.client.get('/')
|
||||||
self.assertContains(response, "example: foobar")
|
self.assertContains(response, "example: foobar")
|
||||||
self.assertEqual(response['Content-Type'], 'text/html')
|
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
|
||||||
|
|
||||||
def test_not_found_html_view(self):
|
def test_not_found_html_view(self):
|
||||||
response = self.client.get('/not_found')
|
response = self.client.get('/not_found')
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
self.assertEqual(response.content, six.b("404 Not Found"))
|
self.assertEqual(response.content, six.b("404 Not Found"))
|
||||||
self.assertEqual(response['Content-Type'], 'text/html')
|
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
|
||||||
|
|
||||||
def test_permission_denied_html_view(self):
|
def test_permission_denied_html_view(self):
|
||||||
response = self.client.get('/permission_denied')
|
response = self.client.get('/permission_denied')
|
||||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
self.assertEqual(response.content, six.b("403 Forbidden"))
|
self.assertEqual(response.content, six.b("403 Forbidden"))
|
||||||
self.assertEqual(response['Content-Type'], 'text/html')
|
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
|
||||||
|
|
||||||
|
|
||||||
class TemplateHTMLRendererExceptionTests(TestCase):
|
class TemplateHTMLRendererExceptionTests(TestCase):
|
||||||
|
@ -109,10 +109,10 @@ class TemplateHTMLRendererExceptionTests(TestCase):
|
||||||
response = self.client.get('/not_found')
|
response = self.client.get('/not_found')
|
||||||
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
|
||||||
self.assertEqual(response.content, six.b("404: Not found"))
|
self.assertEqual(response.content, six.b("404: Not found"))
|
||||||
self.assertEqual(response['Content-Type'], 'text/html')
|
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
|
||||||
|
|
||||||
def test_permission_denied_html_view_with_template(self):
|
def test_permission_denied_html_view_with_template(self):
|
||||||
response = self.client.get('/permission_denied')
|
response = self.client.get('/permission_denied')
|
||||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||||
self.assertEqual(response.content, six.b("403: Permission denied"))
|
self.assertEqual(response.content, six.b("403: Permission denied"))
|
||||||
self.assertEqual(response['Content-Type'], 'text/html')
|
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
|
||||||
|
|
|
@ -12,15 +12,14 @@ factory = RequestFactory()
|
||||||
class MockJSONRenderer(BaseRenderer):
|
class MockJSONRenderer(BaseRenderer):
|
||||||
media_type = 'application/json'
|
media_type = 'application/json'
|
||||||
|
|
||||||
|
|
||||||
class MockHTMLRenderer(BaseRenderer):
|
class MockHTMLRenderer(BaseRenderer):
|
||||||
media_type = 'text/html'
|
media_type = 'text/html'
|
||||||
|
|
||||||
|
|
||||||
class NoCharsetSpecifiedRenderer(BaseRenderer):
|
class NoCharsetSpecifiedRenderer(BaseRenderer):
|
||||||
media_type = 'my/media'
|
media_type = 'my/media'
|
||||||
|
|
||||||
class CharsetSpecifiedRenderer(BaseRenderer):
|
|
||||||
media_type = 'my/media'
|
|
||||||
charset = 'mycharset'
|
|
||||||
|
|
||||||
class TestAcceptedMediaType(TestCase):
|
class TestAcceptedMediaType(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -32,32 +31,15 @@ class TestAcceptedMediaType(TestCase):
|
||||||
|
|
||||||
def test_client_without_accept_use_renderer(self):
|
def test_client_without_accept_use_renderer(self):
|
||||||
request = Request(factory.get('/'))
|
request = Request(factory.get('/'))
|
||||||
accepted_renderer, accepted_media_type, charset = self.select_renderer(request)
|
accepted_renderer, accepted_media_type = self.select_renderer(request)
|
||||||
self.assertEqual(accepted_media_type, 'application/json')
|
self.assertEqual(accepted_media_type, 'application/json')
|
||||||
|
|
||||||
def test_client_underspecifies_accept_use_renderer(self):
|
def test_client_underspecifies_accept_use_renderer(self):
|
||||||
request = Request(factory.get('/', HTTP_ACCEPT='*/*'))
|
request = Request(factory.get('/', HTTP_ACCEPT='*/*'))
|
||||||
accepted_renderer, accepted_media_type, charset = self.select_renderer(request)
|
accepted_renderer, accepted_media_type = self.select_renderer(request)
|
||||||
self.assertEqual(accepted_media_type, 'application/json')
|
self.assertEqual(accepted_media_type, 'application/json')
|
||||||
|
|
||||||
def test_client_overspecifies_accept_use_client(self):
|
def test_client_overspecifies_accept_use_client(self):
|
||||||
request = Request(factory.get('/', HTTP_ACCEPT='application/json; indent=8'))
|
request = Request(factory.get('/', HTTP_ACCEPT='application/json; indent=8'))
|
||||||
accepted_renderer, accepted_media_type, charset = self.select_renderer(request)
|
accepted_renderer, accepted_media_type = self.select_renderer(request)
|
||||||
self.assertEqual(accepted_media_type, 'application/json; indent=8')
|
self.assertEqual(accepted_media_type, 'application/json; indent=8')
|
||||||
|
|
||||||
class TestCharset(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
self.renderers = [NoCharsetSpecifiedRenderer()]
|
|
||||||
self.negotiator = DefaultContentNegotiation()
|
|
||||||
|
|
||||||
def test_returns_none_if_no_charset_set(self):
|
|
||||||
request = Request(factory.get('/'))
|
|
||||||
renderers = [NoCharsetSpecifiedRenderer()]
|
|
||||||
_, _, charset = self.negotiator.select_renderer(request, renderers)
|
|
||||||
self.assertIsNone(charset)
|
|
||||||
|
|
||||||
def test_returns_attribute_from_renderer_if_charset_is_set(self):
|
|
||||||
request = Request(factory.get('/'))
|
|
||||||
renderers = [CharsetSpecifiedRenderer()]
|
|
||||||
_, _, charset = self.negotiator.select_renderer(request, renderers)
|
|
||||||
self.assertEquals(CharsetSpecifiedRenderer.charset, charset)
|
|
|
@ -12,6 +12,7 @@ from rest_framework.renderers import (
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framework.compat import six
|
from rest_framework.compat import six
|
||||||
|
|
||||||
|
|
||||||
class MockPickleRenderer(BaseRenderer):
|
class MockPickleRenderer(BaseRenderer):
|
||||||
media_type = 'application/pickle'
|
media_type = 'application/pickle'
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ class MockPickleRenderer(BaseRenderer):
|
||||||
class MockJsonRenderer(BaseRenderer):
|
class MockJsonRenderer(BaseRenderer):
|
||||||
media_type = 'application/json'
|
media_type = 'application/json'
|
||||||
|
|
||||||
|
|
||||||
class MockTextMediaRenderer(BaseRenderer):
|
class MockTextMediaRenderer(BaseRenderer):
|
||||||
media_type = 'text/html'
|
media_type = 'text/html'
|
||||||
|
|
||||||
|
@ -44,6 +46,7 @@ class RendererB(BaseRenderer):
|
||||||
def render(self, data, media_type=None, renderer_context=None):
|
def render(self, data, media_type=None, renderer_context=None):
|
||||||
return RENDERER_B_SERIALIZER(data)
|
return RENDERER_B_SERIALIZER(data)
|
||||||
|
|
||||||
|
|
||||||
class RendererC(RendererB):
|
class RendererC(RendererB):
|
||||||
media_type = 'mock/rendererc'
|
media_type = 'mock/rendererc'
|
||||||
format = 'formatc'
|
format = 'formatc'
|
||||||
|
@ -56,6 +59,14 @@ class MockView(APIView):
|
||||||
def get(self, request, **kwargs):
|
def get(self, request, **kwargs):
|
||||||
return Response(DUMMYCONTENT, status=DUMMYSTATUS)
|
return Response(DUMMYCONTENT, status=DUMMYSTATUS)
|
||||||
|
|
||||||
|
|
||||||
|
class MockViewSettingCharset(APIView):
|
||||||
|
renderer_classes = (RendererA, RendererB, RendererC)
|
||||||
|
|
||||||
|
def get(self, request, **kwargs):
|
||||||
|
return Response(DUMMYCONTENT, status=DUMMYSTATUS, charset='setbyview')
|
||||||
|
|
||||||
|
|
||||||
class HTMLView(APIView):
|
class HTMLView(APIView):
|
||||||
renderer_classes = (BrowsableAPIRenderer, )
|
renderer_classes = (BrowsableAPIRenderer, )
|
||||||
|
|
||||||
|
@ -70,6 +81,7 @@ class HTMLView1(APIView):
|
||||||
return Response('text')
|
return Response('text')
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
|
url(r'^setbyview$', MockViewSettingCharset.as_view(renderer_classes=[RendererA, RendererB, RendererC])),
|
||||||
url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderer_classes=[RendererA, RendererB, RendererC])),
|
url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderer_classes=[RendererA, RendererB, RendererC])),
|
||||||
url(r'^$', MockView.as_view(renderer_classes=[RendererA, RendererB, RendererC])),
|
url(r'^$', MockView.as_view(renderer_classes=[RendererA, RendererB, RendererC])),
|
||||||
url(r'^html$', HTMLView.as_view()),
|
url(r'^html$', HTMLView.as_view()),
|
||||||
|
@ -178,43 +190,37 @@ class Issue122Tests(TestCase):
|
||||||
"""
|
"""
|
||||||
self.client.get('/html1')
|
self.client.get('/html1')
|
||||||
|
|
||||||
|
|
||||||
class Issue807Testts(TestCase):
|
class Issue807Testts(TestCase):
|
||||||
"""
|
"""
|
||||||
Covers #807
|
Covers #807
|
||||||
"""
|
"""
|
||||||
|
|
||||||
urls = 'rest_framework.tests.response'
|
urls = 'rest_framework.tests.response'
|
||||||
|
|
||||||
def test_does_not_append_charset_by_default(self):
|
def test_does_not_append_charset_by_default(self):
|
||||||
"""
|
"""
|
||||||
For backwards compatibility `REST_FRAMEWORK['DEFAULT_CHARSET']` defaults
|
Renderers don't include a charset unless set explicitly.
|
||||||
to None, so that all legacy code works as expected.
|
|
||||||
"""
|
"""
|
||||||
headers = {"HTTP_ACCEPT": RendererA.media_type}
|
headers = {"HTTP_ACCEPT": RendererA.media_type}
|
||||||
resp = self.client.get('/', **headers)
|
resp = self.client.get('/', **headers)
|
||||||
self.assertEquals(RendererA.media_type, resp['Content-Type'])
|
self.assertEqual(RendererA.media_type, resp['Content-Type'])
|
||||||
|
|
||||||
def test_if_there_is_charset_specified_on_renderer_it_gets_appended(self):
|
def test_if_there_is_charset_specified_on_renderer_it_gets_appended(self):
|
||||||
"""
|
"""
|
||||||
If renderer class has charset attribute declared, it gets appended
|
If renderer class has charset attribute declared, it gets appended
|
||||||
to Response's Content-Type
|
to Response's Content-Type
|
||||||
"""
|
"""
|
||||||
resp = self.client.get('/?format=%s' % RendererC.format)
|
headers = {"HTTP_ACCEPT": RendererC.media_type}
|
||||||
expected = "{0}; charset={1}".format(RendererC.media_type, RendererC.charset)
|
|
||||||
self.assertEquals(expected, resp['Content-Type'])
|
|
||||||
|
|
||||||
def test_if_there_is_default_charset_specified_it_gets_appended(self):
|
|
||||||
"""
|
|
||||||
If user defines `REST_FRAMEWORK['DEFAULT_CHARSET']` it will get appended
|
|
||||||
to Content-Type of all responses.
|
|
||||||
"""
|
|
||||||
original_default_charset = api_settings.DEFAULT_CHARSET
|
|
||||||
api_settings.DEFAULT_CHARSET = "utf-8"
|
|
||||||
headers = {'HTTP_ACCEPT': RendererA.media_type}
|
|
||||||
resp = self.client.get('/', **headers)
|
resp = self.client.get('/', **headers)
|
||||||
expected = "{0}; charset={1}".format(
|
expected = "{0}; charset={1}".format(RendererC.media_type, RendererC.charset)
|
||||||
RendererA.media_type,
|
self.assertEqual(expected, resp['Content-Type'])
|
||||||
api_settings.DEFAULT_CHARSET
|
|
||||||
)
|
def test_charset_set_explictly_on_response(self):
|
||||||
self.assertEquals(expected, resp['Content-Type'])
|
"""
|
||||||
api_settings.DEFAULT_CHARSET = original_default_charset
|
The charset may be set explictly on the response.
|
||||||
|
"""
|
||||||
|
headers = {"HTTP_ACCEPT": RendererC.media_type}
|
||||||
|
resp = self.client.get('/setbyview', **headers)
|
||||||
|
expected = "{0}; charset={1}".format(RendererC.media_type, 'setbyview')
|
||||||
|
self.assertEqual(expected, resp['Content-Type'])
|
||||||
|
|
|
@ -183,9 +183,7 @@ class APIView(View):
|
||||||
return conneg.select_renderer(request, renderers, self.format_kwarg)
|
return conneg.select_renderer(request, renderers, self.format_kwarg)
|
||||||
except Exception:
|
except Exception:
|
||||||
if force:
|
if force:
|
||||||
charset = renderers[0].charset
|
return (renderers[0], renderers[0].media_type)
|
||||||
charset = charset if charset is not None else api_settings.DEFAULT_CHARSET
|
|
||||||
return (renderers[0], renderers[0].media_type, renderers[0].charset)
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def perform_authentication(self, request):
|
def perform_authentication(self, request):
|
||||||
|
@ -252,10 +250,7 @@ class APIView(View):
|
||||||
|
|
||||||
# Perform content negotiation and store the accepted info on the request
|
# Perform content negotiation and store the accepted info on the request
|
||||||
neg = self.perform_content_negotiation(request)
|
neg = self.perform_content_negotiation(request)
|
||||||
renderer, media_type, charset = neg
|
request.accepted_renderer, request.accepted_media_type = neg
|
||||||
request.accepted_renderer = renderer
|
|
||||||
request.accepted_media_type = media_type
|
|
||||||
request.accepted_charset = charset
|
|
||||||
|
|
||||||
def finalize_response(self, request, response, *args, **kwargs):
|
def finalize_response(self, request, response, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -270,16 +265,11 @@ class APIView(View):
|
||||||
if isinstance(response, Response):
|
if isinstance(response, Response):
|
||||||
if not getattr(request, 'accepted_renderer', None):
|
if not getattr(request, 'accepted_renderer', None):
|
||||||
neg = self.perform_content_negotiation(request, force=True)
|
neg = self.perform_content_negotiation(request, force=True)
|
||||||
renderer, media_type, charset = neg
|
request.accepted_renderer, request.accepted_media_type = neg
|
||||||
request.accepted_renderer = renderer
|
|
||||||
request.accepted_media_type = media_type
|
|
||||||
|
|
||||||
response.accepted_renderer = request.accepted_renderer
|
response.accepted_renderer = request.accepted_renderer
|
||||||
response.accepted_media_type = request.accepted_media_type
|
response.accepted_media_type = request.accepted_media_type
|
||||||
response.renderer_context = self.get_renderer_context()
|
response.renderer_context = self.get_renderer_context()
|
||||||
charset = request.accepted_renderer.charset
|
|
||||||
charset = charset if charset else api_settings.DEFAULT_CHARSET
|
|
||||||
response.charset = charset
|
|
||||||
|
|
||||||
for key, value in self.headers.items():
|
for key, value in self.headers.items():
|
||||||
response[key] = value
|
response[key] = value
|
||||||
|
|
Loading…
Reference in New Issue
Block a user