Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
django-rest-framework
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
django-rest-framework
Commits
ebe959b5
Commit
ebe959b5
authored
May 18, 2013
by
Karol Majta
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
charset param gets now appended to response's Content-Type. Closes #807
parent
b950b025
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
112 additions
and
20 deletions
+112
-20
rest_framework/negotiation.py
+8
-2
rest_framework/renderers.py
+1
-1
rest_framework/response.py
+6
-2
rest_framework/settings.py
+2
-0
rest_framework/tests/negotiation.py
+30
-6
rest_framework/tests/response.py
+52
-6
rest_framework/views.py
+13
-3
No files found.
rest_framework/negotiation.py
View file @
ebe959b5
...
@@ -58,11 +58,17 @@ class DefaultContentNegotiation(BaseContentNegotiation):
...
@@ -58,11 +58,17 @@ 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'
re
turn
renderer
,
renderer
.
media_type
re
nderer_and_media_type
=
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'
return
renderer
,
media_type
renderer_and_media_type
=
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
)
...
...
rest_framework/renderers.py
View file @
ebe959b5
...
@@ -36,11 +36,11 @@ class BaseRenderer(object):
...
@@ -36,11 +36,11 @@ class BaseRenderer(object):
media_type
=
None
media_type
=
None
format
=
None
format
=
None
charset
=
None
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.
...
...
rest_framework/response.py
View file @
ebe959b5
...
@@ -39,14 +39,18 @@ class Response(SimpleTemplateResponse):
...
@@ -39,14 +39,18 @@ 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
:
self
[
'Content-Type'
]
=
media_type
ct
=
"{0}; charset={1}"
.
format
(
media_type
,
charset
)
else
:
ct
=
media_type
self
[
'Content-Type'
]
=
ct
return
renderer
.
render
(
self
.
data
,
media_type
,
context
)
return
renderer
.
render
(
self
.
data
,
media_type
,
context
)
@property
@property
...
...
rest_framework/settings.py
View file @
ebe959b5
...
@@ -83,6 +83,8 @@ DEFAULTS = {
...
@@ -83,6 +83,8 @@ 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
,
),
),
...
...
rest_framework/tests/negotiation.py
View file @
ebe959b5
...
@@ -3,18 +3,24 @@ from django.test import TestCase
...
@@ -3,18 +3,24 @@ from django.test import TestCase
from
django.test.client
import
RequestFactory
from
django.test.client
import
RequestFactory
from
rest_framework.negotiation
import
DefaultContentNegotiation
from
rest_framework.negotiation
import
DefaultContentNegotiation
from
rest_framework.request
import
Request
from
rest_framework.request
import
Request
from
rest_framework.renderers
import
BaseRenderer
factory
=
RequestFactory
()
factory
=
RequestFactory
()
class
MockJSONRenderer
(
object
):
class
MockJSONRenderer
(
BaseRenderer
):
media_type
=
'application/json'
media_type
=
'application/json'
class
MockHTMLRenderer
(
BaseRenderer
):
class
MockHTMLRenderer
(
object
):
media_type
=
'text/html'
media_type
=
'text/html'
class
NoCharsetSpecifiedRenderer
(
BaseRenderer
):
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
):
...
@@ -26,15 +32,32 @@ class TestAcceptedMediaType(TestCase):
...
@@ -26,15 +32,32 @@ 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
=
self
.
select_renderer
(
request
)
accepted_renderer
,
accepted_media_type
,
charset
=
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
=
self
.
select_renderer
(
request
)
accepted_renderer
,
accepted_media_type
,
charset
=
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
=
self
.
select_renderer
(
request
)
accepted_renderer
,
accepted_media_type
,
charset
=
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
)
\ No newline at end of file
rest_framework/tests/response.py
View file @
ebe959b5
...
@@ -12,7 +12,6 @@ from rest_framework.renderers import (
...
@@ -12,7 +12,6 @@ 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'
...
@@ -20,6 +19,8 @@ class MockPickleRenderer(BaseRenderer):
...
@@ -20,6 +19,8 @@ class MockPickleRenderer(BaseRenderer):
class
MockJsonRenderer
(
BaseRenderer
):
class
MockJsonRenderer
(
BaseRenderer
):
media_type
=
'application/json'
media_type
=
'application/json'
class
MockTextMediaRenderer
(
BaseRenderer
):
media_type
=
'text/html'
DUMMYSTATUS
=
status
.
HTTP_200_OK
DUMMYSTATUS
=
status
.
HTTP_200_OK
DUMMYCONTENT
=
'dummycontent'
DUMMYCONTENT
=
'dummycontent'
...
@@ -43,14 +44,18 @@ class RendererB(BaseRenderer):
...
@@ -43,14 +44,18 @@ 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
):
media_type
=
'mock/rendererc'
format
=
'formatc'
charset
=
"rendererc"
class
MockView
(
APIView
):
class
MockView
(
APIView
):
renderer_classes
=
(
RendererA
,
RendererB
)
renderer_classes
=
(
RendererA
,
RendererB
,
RendererC
)
def
get
(
self
,
request
,
**
kwargs
):
def
get
(
self
,
request
,
**
kwargs
):
return
Response
(
DUMMYCONTENT
,
status
=
DUMMYSTATUS
)
return
Response
(
DUMMYCONTENT
,
status
=
DUMMYSTATUS
)
class
HTMLView
(
APIView
):
class
HTMLView
(
APIView
):
renderer_classes
=
(
BrowsableAPIRenderer
,
)
renderer_classes
=
(
BrowsableAPIRenderer
,
)
...
@@ -64,10 +69,9 @@ class HTMLView1(APIView):
...
@@ -64,10 +69,9 @@ class HTMLView1(APIView):
def
get
(
self
,
request
,
**
kwargs
):
def
get
(
self
,
request
,
**
kwargs
):
return
Response
(
'text'
)
return
Response
(
'text'
)
urlpatterns
=
patterns
(
''
,
urlpatterns
=
patterns
(
''
,
url
(
r'^.*\.(?P<format>.+)$'
,
MockView
.
as_view
(
renderer_classes
=
[
RendererA
,
RendererB
])),
url
(
r'^.*\.(?P<format>.+)$'
,
MockView
.
as_view
(
renderer_classes
=
[
RendererA
,
RendererB
,
RendererC
])),
url
(
r'^$'
,
MockView
.
as_view
(
renderer_classes
=
[
RendererA
,
RendererB
])),
url
(
r'^$'
,
MockView
.
as_view
(
renderer_classes
=
[
RendererA
,
RendererB
,
RendererC
])),
url
(
r'^html$'
,
HTMLView
.
as_view
()),
url
(
r'^html$'
,
HTMLView
.
as_view
()),
url
(
r'^html1$'
,
HTMLView1
.
as_view
()),
url
(
r'^html1$'
,
HTMLView1
.
as_view
()),
url
(
r'^restframework'
,
include
(
'rest_framework.urls'
,
namespace
=
'rest_framework'
))
url
(
r'^restframework'
,
include
(
'rest_framework.urls'
,
namespace
=
'rest_framework'
))
...
@@ -173,3 +177,44 @@ class Issue122Tests(TestCase):
...
@@ -173,3 +177,44 @@ class Issue122Tests(TestCase):
Test if no infinite recursion occurs.
Test if no infinite recursion occurs.
"""
"""
self
.
client
.
get
(
'/html1'
)
self
.
client
.
get
(
'/html1'
)
class
Issue807Testts
(
TestCase
):
"""
Covers #807
"""
urls
=
'rest_framework.tests.response'
def
test_does_not_append_charset_by_default
(
self
):
"""
For backwards compatibility `REST_FRAMEWORK['DEFAULT_CHARSET']` defaults
to None, so that all legacy code works as expected.
"""
headers
=
{
"HTTP_ACCEPT"
:
RendererA
.
media_type
}
resp
=
self
.
client
.
get
(
'/'
,
**
headers
)
self
.
assertEquals
(
RendererA
.
media_type
,
resp
[
'Content-Type'
])
def
test_if_there_is_charset_specified_on_renderer_it_gets_appended
(
self
):
"""
If renderer class has charset attribute declared, it gets appended
to Response's Content-Type
"""
resp
=
self
.
client
.
get
(
'/?format=
%
s'
%
RendererC
.
format
)
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
)
expected
=
"{0}; charset={1}"
.
format
(
RendererA
.
media_type
,
api_settings
.
DEFAULT_CHARSET
)
self
.
assertEquals
(
expected
,
resp
[
'Content-Type'
])
api_settings
.
DEFAULT_CHARSET
=
original_default_charset
\ No newline at end of file
rest_framework/views.py
View file @
ebe959b5
...
@@ -183,7 +183,9 @@ class APIView(View):
...
@@ -183,7 +183,9 @@ 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
:
return
(
renderers
[
0
],
renderers
[
0
]
.
media_type
)
charset
=
renderers
[
0
]
.
charset
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
):
...
@@ -250,7 +252,10 @@ class APIView(View):
...
@@ -250,7 +252,10 @@ 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
)
request
.
accepted_renderer
,
request
.
accepted_media_type
=
neg
renderer
,
media_type
,
charset
=
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
):
"""
"""
...
@@ -265,11 +270,16 @@ class APIView(View):
...
@@ -265,11 +270,16 @@ 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
)
request
.
accepted_renderer
,
request
.
accepted_media_type
=
neg
renderer
,
media_type
,
charset
=
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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment