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
9d8bce8f
Commit
9d8bce8f
authored
Oct 05, 2012
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove Parser.can_handle_request()
parent
3e862c77
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
72 additions
and
51 deletions
+72
-51
rest_framework/negotiation.py
+10
-0
rest_framework/parsers.py
+1
-16
rest_framework/request.py
+16
-22
rest_framework/tests/decorators.py
+6
-2
rest_framework/tests/request.py
+6
-6
rest_framework/views.py
+33
-5
No files found.
rest_framework/negotiation.py
View file @
9d8bce8f
...
...
@@ -11,6 +11,16 @@ class BaseContentNegotiation(object):
class
DefaultContentNegotiation
(
object
):
settings
=
api_settings
def
select_parser
(
self
,
parsers
,
media_type
):
"""
Given a list of parsers and a media type, return the appropriate
parser to handle the incoming request.
"""
for
parser
in
parsers
:
if
media_type_matches
(
parser
.
media_type
,
media_type
):
return
parser
return
None
def
negotiate
(
self
,
request
,
renderers
,
format
=
None
,
force
=
False
):
"""
Given a request and a list of renderers, return a two-tuple of:
...
...
rest_framework/parsers.py
View file @
9d8bce8f
...
...
@@ -15,11 +15,9 @@ from django.http import QueryDict
from
django.http.multipartparser
import
MultiPartParser
as
DjangoMultiPartParser
from
django.http.multipartparser
import
MultiPartParserError
from
django.utils
import
simplejson
as
json
from
rest_framework.compat
import
yaml
from
rest_framework.compat
import
yaml
,
ETParseError
from
rest_framework.exceptions
import
ParseError
from
rest_framework.utils.mediatypes
import
media_type_matches
from
xml.etree
import
ElementTree
as
ET
from
rest_framework.compat
import
ETParseError
from
xml.parsers.expat
import
ExpatError
import
datetime
import
decimal
...
...
@@ -40,19 +38,6 @@ class BaseParser(object):
media_type
=
None
def
can_handle_request
(
self
,
content_type
):
"""
Returns :const:`True` if this parser is able to deal with the given *content_type*.
The default implementation for this function is to check the *content_type*
argument against the :attr:`media_type` attribute set on the class to see if
they match.
This may be overridden to provide for other behavior, but typically you'll
instead want to just set the :attr:`media_type` attribute on the class.
"""
return
media_type_matches
(
self
.
media_type
,
content_type
)
def
parse
(
self
,
string_or_stream
,
**
opts
):
"""
The main entry point to parsers. This is a light wrapper around
...
...
rest_framework/request.py
View file @
9d8bce8f
...
...
@@ -34,8 +34,8 @@ def clone_request(request, method):
HTTP method. Used for checking permissions against other methods.
"""
ret
=
Request
(
request
.
_request
,
request
.
parser
_classe
s
,
request
.
authenticat
ion_classe
s
)
request
.
parsers
,
request
.
authenticat
or
s
)
ret
.
_data
=
request
.
_data
ret
.
_files
=
request
.
_files
ret
.
_content_type
=
request
.
_content_type
...
...
@@ -60,27 +60,20 @@ class Request(object):
_CONTENT_PARAM
=
api_settings
.
FORM_CONTENT_OVERRIDE
_CONTENTTYPE_PARAM
=
api_settings
.
FORM_CONTENTTYPE_OVERRIDE
def
__init__
(
self
,
request
,
parser_classes
=
None
,
authentication_classes
=
None
):
def
__init__
(
self
,
request
,
parsers
=
None
,
authenticators
=
None
,
negotiator
=
None
):
self
.
_request
=
request
self
.
parser_classes
=
parser_classes
or
()
self
.
authentication_classes
=
authentication_classes
or
()
self
.
parsers
=
parsers
or
()
self
.
authenticators
=
authenticators
or
()
self
.
negotiator
=
negotiator
or
self
.
_default_negotiator
()
self
.
_data
=
Empty
self
.
_files
=
Empty
self
.
_method
=
Empty
self
.
_content_type
=
Empty
self
.
_stream
=
Empty
def
get_parsers
(
self
):
"""
Instantiates and returns the list of parsers the request will use.
"""
return
[
parser
()
for
parser
in
self
.
parser_classes
]
def
get_authentications
(
self
):
"""
Instantiates and returns the list of parsers the request will use.
"""
return
[
authentication
()
for
authentication
in
self
.
authentication_classes
]
def
_default_negotiator
(
self
):
return
api_settings
.
DEFAULT_CONTENT_NEGOTIATION
()
@property
def
method
(
self
):
...
...
@@ -254,8 +247,11 @@ class Request(object):
if
self
.
stream
is
None
or
self
.
content_type
is
None
:
return
(
None
,
None
)
for
parser
in
self
.
get_parsers
():
if
parser
.
can_handle_request
(
self
.
content_type
):
parser
=
self
.
negotiator
.
select_parser
(
self
.
parsers
,
self
.
content_type
)
if
not
parser
:
raise
exceptions
.
UnsupportedMediaType
(
self
.
_content_type
)
parsed
=
parser
.
parse
(
self
.
stream
,
meta
=
self
.
META
,
upload_handlers
=
self
.
upload_handlers
)
# Parser classes may return the raw data, or a
...
...
@@ -265,15 +261,13 @@ class Request(object):
except
AttributeError
:
return
(
parsed
,
None
)
raise
exceptions
.
UnsupportedMediaType
(
self
.
_content_type
)
def
_authenticate
(
self
):
"""
Attempt to authenticate the request using each authentication instance in turn.
Returns a two-tuple of (user, authtoken).
"""
for
authenticat
ion
in
self
.
get_authentications
()
:
user_auth_tuple
=
authenticat
ion
.
authenticate
(
self
)
for
authenticat
or
in
self
.
authenticators
:
user_auth_tuple
=
authenticat
or
.
authenticate
(
self
)
if
not
user_auth_tuple
is
None
:
return
user_auth_tuple
return
self
.
_not_authenticated
()
...
...
rest_framework/tests/decorators.py
View file @
9d8bce8f
...
...
@@ -65,7 +65,9 @@ class DecoratorTestCase(TestCase):
@api_view
([
'GET'
])
@parser_classes
([
JSONParser
])
def
view
(
request
):
self
.
assertEqual
(
request
.
parser_classes
,
[
JSONParser
])
self
.
assertEqual
(
len
(
request
.
parsers
),
1
)
self
.
assertTrue
(
isinstance
(
request
.
parsers
[
0
],
JSONParser
))
return
Response
({})
request
=
self
.
factory
.
get
(
'/'
)
...
...
@@ -76,7 +78,9 @@ class DecoratorTestCase(TestCase):
@api_view
([
'GET'
])
@authentication_classes
([
BasicAuthentication
])
def
view
(
request
):
self
.
assertEqual
(
request
.
authentication_classes
,
[
BasicAuthentication
])
self
.
assertEqual
(
len
(
request
.
authenticators
),
1
)
self
.
assertTrue
(
isinstance
(
request
.
authenticators
[
0
],
BasicAuthentication
))
return
Response
({})
request
=
self
.
factory
.
get
(
'/'
)
...
...
rest_framework/tests/request.py
View file @
9d8bce8f
...
...
@@ -61,7 +61,7 @@ class TestContentParsing(TestCase):
"""
data
=
{
'qwerty'
:
'uiop'
}
request
=
Request
(
factory
.
post
(
'/'
,
data
))
request
.
parser
_classes
=
(
FormParser
,
MultiPartParser
)
request
.
parser
s
=
(
FormParser
(),
MultiPartParser
()
)
self
.
assertEqual
(
request
.
DATA
.
items
(),
data
.
items
())
def
test_request_DATA_with_text_content
(
self
):
...
...
@@ -72,7 +72,7 @@ class TestContentParsing(TestCase):
content
=
'qwerty'
content_type
=
'text/plain'
request
=
Request
(
factory
.
post
(
'/'
,
content
,
content_type
=
content_type
))
request
.
parser
_classes
=
(
PlainTextParser
,)
request
.
parser
s
=
(
PlainTextParser
()
,)
self
.
assertEqual
(
request
.
DATA
,
content
)
def
test_request_POST_with_form_content
(
self
):
...
...
@@ -81,7 +81,7 @@ class TestContentParsing(TestCase):
"""
data
=
{
'qwerty'
:
'uiop'
}
request
=
Request
(
factory
.
post
(
'/'
,
data
))
request
.
parser
_classes
=
(
FormParser
,
MultiPartParser
)
request
.
parser
s
=
(
FormParser
(),
MultiPartParser
()
)
self
.
assertEqual
(
request
.
POST
.
items
(),
data
.
items
())
def
test_standard_behaviour_determines_form_content_PUT
(
self
):
...
...
@@ -99,7 +99,7 @@ class TestContentParsing(TestCase):
else
:
request
=
Request
(
factory
.
put
(
'/'
,
data
))
request
.
parser
_classes
=
(
FormParser
,
MultiPartParser
)
request
.
parser
s
=
(
FormParser
(),
MultiPartParser
()
)
self
.
assertEqual
(
request
.
DATA
.
items
(),
data
.
items
())
def
test_standard_behaviour_determines_non_form_content_PUT
(
self
):
...
...
@@ -110,7 +110,7 @@ class TestContentParsing(TestCase):
content
=
'qwerty'
content_type
=
'text/plain'
request
=
Request
(
factory
.
put
(
'/'
,
content
,
content_type
=
content_type
))
request
.
parser
_classes
=
(
PlainTextParser
,
)
request
.
parser
s
=
(
PlainTextParser
()
,
)
self
.
assertEqual
(
request
.
DATA
,
content
)
def
test_overloaded_behaviour_allows_content_tunnelling
(
self
):
...
...
@@ -124,7 +124,7 @@ class TestContentParsing(TestCase):
Request
.
_CONTENTTYPE_PARAM
:
content_type
}
request
=
Request
(
factory
.
post
(
'/'
,
data
))
request
.
parser
_classes
=
(
PlainTextParser
,
)
request
.
parser
s
=
(
PlainTextParser
()
,
)
self
.
assertEqual
(
request
.
DATA
,
content
)
# def test_accessing_post_after_data_form(self):
...
...
rest_framework/views.py
View file @
9d8bce8f
...
...
@@ -70,6 +70,7 @@ class APIView(View):
as an attribute on the callable function. This allows us to discover
information about the view when we do URL reverse lookups.
"""
# TODO: deprecate?
view
=
super
(
APIView
,
cls
)
.
as_view
(
**
initkwargs
)
view
.
cls_instance
=
cls
(
**
initkwargs
)
return
view
...
...
@@ -84,6 +85,7 @@ class APIView(View):
@property
def
default_response_headers
(
self
):
# TODO: Only vary by accept if multiple renderers
return
{
'Allow'
:
', '
.
join
(
self
.
allowed_methods
),
'Vary'
:
'Accept'
...
...
@@ -94,6 +96,7 @@ class APIView(View):
Return the resource or view class name for use as this view's name.
Override to customize.
"""
# TODO: deprecate?
name
=
self
.
__class__
.
__name__
name
=
_remove_trailing_string
(
name
,
'View'
)
return
_camelcase_to_spaces
(
name
)
...
...
@@ -103,6 +106,7 @@ class APIView(View):
Return the resource or view docstring for use as this view's description.
Override to customize.
"""
# TODO: deprecate?
description
=
self
.
__doc__
or
''
description
=
_remove_leading_indent
(
description
)
if
html
:
...
...
@@ -113,6 +117,7 @@ class APIView(View):
"""
Apply HTML markup to the description of this view.
"""
# TODO: deprecate?
if
apply_markdown
:
description
=
apply_markdown
(
description
)
else
:
...
...
@@ -137,6 +142,8 @@ class APIView(View):
"""
raise
exceptions
.
Throttled
(
wait
)
# API policy instantiation methods
def
get_format_suffix
(
self
,
**
kwargs
):
"""
Determine if the request includes a '.json' style format suffix
...
...
@@ -144,12 +151,24 @@ class APIView(View):
if
self
.
settings
.
FORMAT_SUFFIX_KWARG
:
return
kwargs
.
get
(
self
.
settings
.
FORMAT_SUFFIX_KWARG
)
def
get_renderers
(
self
,
format
=
None
):
def
get_renderers
(
self
):
"""
Instantiates and returns the list of renderers that this view can use.
"""
return
[
renderer
(
self
)
for
renderer
in
self
.
renderer_classes
]
def
get_parsers
(
self
):
"""
Instantiates and returns the list of renderers that this view can use.
"""
return
[
parser
()
for
parser
in
self
.
parser_classes
]
def
get_authenticators
(
self
):
"""
Instantiates and returns the list of renderers that this view can use.
"""
return
[
auth
()
for
auth
in
self
.
authentication_classes
]
def
get_permissions
(
self
):
"""
Instantiates and returns the list of permissions that this view requires.
...
...
@@ -166,7 +185,11 @@ class APIView(View):
"""
Instantiate and return the content negotiation class to use.
"""
return
self
.
content_negotiation_class
()
if
not
getattr
(
self
,
'_negotiator'
,
None
):
self
.
_negotiator
=
self
.
content_negotiation_class
()
return
self
.
_negotiator
# API policy implementation methods
def
perform_content_negotiation
(
self
,
request
,
force
=
False
):
"""
...
...
@@ -193,19 +216,24 @@ class APIView(View):
if
not
throttle
.
allow_request
(
request
):
self
.
throttled
(
request
,
throttle
.
wait
())
# Dispatch methods
def
initialize_request
(
self
,
request
,
*
args
,
**
kargs
):
"""
Returns the initial request object.
"""
return
Request
(
request
,
parser_classes
=
self
.
parser_classes
,
authentication_classes
=
self
.
authentication_classes
)
return
Request
(
request
,
parsers
=
self
.
get_parsers
(),
authenticators
=
self
.
get_authenticators
(),
negotiator
=
self
.
get_content_negotiator
())
def
initial
(
self
,
request
,
*
args
,
**
kwargs
):
"""
Runs anything that needs to occur prior to calling the method handler
s
.
Runs anything that needs to occur prior to calling the method handler.
"""
self
.
format_kwarg
=
self
.
get_format_suffix
(
**
kwargs
)
# Ensure that the incoming request is permitted
if
not
self
.
has_permission
(
request
):
self
.
permission_denied
(
request
)
self
.
check_throttles
(
request
)
...
...
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