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
5557dfb5
Commit
5557dfb5
authored
Jan 12, 2011
by
Tom Christie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Various cleanups
parent
42825e44
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
93 additions
and
82 deletions
+93
-82
src/rest/emitters.py
+24
-13
src/rest/parsers.py
+11
-12
src/rest/resource.py
+58
-57
No files found.
src/rest/emitters.py
View file @
5557dfb5
...
@@ -4,12 +4,8 @@ import json
...
@@ -4,12 +4,8 @@ import json
from
utils
import
dict2xml
from
utils
import
dict2xml
class
BaseEmitter
(
object
):
class
BaseEmitter
(
object
):
def
__init__
(
self
,
resource
,
request
,
status
,
headers
,
form
):
def
__init__
(
self
,
resource
):
self
.
request
=
request
self
.
resource
=
resource
self
.
resource
=
resource
self
.
status
=
status
self
.
headers
=
headers
self
.
form
=
form
def
emit
(
self
,
output
):
def
emit
(
self
,
output
):
return
output
return
output
...
@@ -18,28 +14,43 @@ class TemplatedEmitter(BaseEmitter):
...
@@ -18,28 +14,43 @@ class TemplatedEmitter(BaseEmitter):
template
=
None
template
=
None
def
emit
(
self
,
output
):
def
emit
(
self
,
output
):
content
=
json
.
dumps
(
output
,
indent
=
4
,
sort_keys
=
True
)
if
output
is
None
:
content
=
''
else
:
content
=
json
.
dumps
(
output
,
indent
=
4
,
sort_keys
=
True
)
template
=
loader
.
get_template
(
self
.
template
)
template
=
loader
.
get_template
(
self
.
template
)
context
=
RequestContext
(
self
.
request
,
{
context
=
RequestContext
(
self
.
re
source
.
re
quest
,
{
'content'
:
content
,
'content'
:
content
,
'status'
:
self
.
status
,
'status'
:
self
.
resource
.
resp_
status
,
'reason'
:
STATUS_CODE_TEXT
.
get
(
self
.
status
,
''
),
'reason'
:
STATUS_CODE_TEXT
.
get
(
self
.
resource
.
resp_
status
,
''
),
'headers'
:
self
.
headers
,
'headers'
:
self
.
resource
.
resp_
headers
,
'resource_name'
:
self
.
resource
.
__class__
.
__name__
,
'resource_name'
:
self
.
resource
.
__class__
.
__name__
,
'resource_doc'
:
self
.
resource
.
__doc__
,
'resource_doc'
:
self
.
resource
.
__doc__
,
'create_form'
:
self
.
form
,
'create_form'
:
self
.
resource
.
form
,
'update_form'
:
self
.
form
,
'update_form'
:
self
.
resource
.
form
,
'request'
:
self
.
request
,
'request'
:
self
.
re
source
.
re
quest
,
'resource'
:
self
.
resource
,
'resource'
:
self
.
resource
,
})
})
# Munge DELETE Response code to allow us to return content
if
self
.
resource
.
resp_status
==
204
:
self
.
resource
.
resp_status
=
200
return
template
.
render
(
context
)
return
template
.
render
(
context
)
class
JSONEmitter
(
BaseEmitter
):
class
JSONEmitter
(
BaseEmitter
):
def
emit
(
self
,
output
):
def
emit
(
self
,
output
):
if
output
is
None
:
# Treat None as no message body, rather than serializing
return
''
return
json
.
dumps
(
output
)
return
json
.
dumps
(
output
)
class
XMLEmitter
(
BaseEmitter
):
class
XMLEmitter
(
BaseEmitter
):
def
emit
(
self
,
output
):
def
emit
(
self
,
output
):
if
output
is
None
:
# Treat None as no message body, rather than serializing
return
''
return
dict2xml
(
output
)
return
dict2xml
(
output
)
class
HTMLEmitter
(
TemplatedEmitter
):
class
HTMLEmitter
(
TemplatedEmitter
):
...
...
src/rest/parsers.py
View file @
5557dfb5
import
json
import
json
class
BaseParser
(
object
):
class
BaseParser
(
object
):
def
__init__
(
self
,
resource
,
request
):
def
__init__
(
self
,
resource
):
self
.
resource
=
resource
self
.
resource
=
resource
self
.
request
=
request
def
parse
(
self
,
input
):
def
parse
(
self
,
input
):
return
{}
return
{}
...
@@ -20,9 +19,9 @@ class FormParser(BaseParser):
...
@@ -20,9 +19,9 @@ class FormParser(BaseParser):
"""The default parser for form data.
"""The default parser for form data.
Return a dict containing a single value for each non-reserved parameter
Return a dict containing a single value for each non-reserved parameter
"""
"""
def
__init__
(
self
,
resource
,
request
):
def
__init__
(
self
,
resource
):
if
request
.
method
==
'PUT'
:
if
re
source
.
re
quest
.
method
==
'PUT'
:
# Fix from piston to force Django to give PUT requests the same
# Fix from piston to force Django to give PUT requests the same
# form processing that POST requests get...
# form processing that POST requests get...
#
#
...
@@ -36,22 +35,22 @@ class FormParser(BaseParser):
...
@@ -36,22 +35,22 @@ class FormParser(BaseParser):
# the first time _load_post_and_files is called (both by wsgi.py and
# the first time _load_post_and_files is called (both by wsgi.py and
# modpython.py). If it's set, the request has to be 'reset' to redo
# modpython.py). If it's set, the request has to be 'reset' to redo
# the query value parsing in POST mode.
# the query value parsing in POST mode.
if
hasattr
(
request
,
'_post'
):
if
hasattr
(
re
source
.
re
quest
,
'_post'
):
del
request
.
_post
del
request
.
_post
del
request
.
_files
del
request
.
_files
try
:
try
:
request
.
method
=
"POST"
re
source
.
re
quest
.
method
=
"POST"
request
.
_load_post_and_files
()
re
source
.
re
quest
.
_load_post_and_files
()
request
.
method
=
"PUT"
re
source
.
re
quest
.
method
=
"PUT"
except
AttributeError
:
except
AttributeError
:
request
.
META
[
'REQUEST_METHOD'
]
=
'POST'
re
source
.
re
quest
.
META
[
'REQUEST_METHOD'
]
=
'POST'
request
.
_load_post_and_files
()
re
source
.
re
quest
.
_load_post_and_files
()
request
.
META
[
'REQUEST_METHOD'
]
=
'PUT'
re
source
.
re
quest
.
META
[
'REQUEST_METHOD'
]
=
'PUT'
#
#
self
.
data
=
{}
self
.
data
=
{}
for
(
key
,
val
)
in
request
.
POST
.
items
():
for
(
key
,
val
)
in
re
source
.
re
quest
.
POST
.
items
():
if
key
not
in
resource
.
RESERVED_PARAMS
:
if
key
not
in
resource
.
RESERVED_PARAMS
:
self
.
data
[
key
]
=
val
self
.
data
[
key
]
=
val
...
...
src/rest/resource.py
View file @
5557dfb5
...
@@ -57,7 +57,7 @@ class Resource(object):
...
@@ -57,7 +57,7 @@ class Resource(object):
"""Make the class callable so it can be used as a Django view."""
"""Make the class callable so it can be used as a Django view."""
self
=
object
.
__new__
(
cls
)
self
=
object
.
__new__
(
cls
)
self
.
__init__
()
self
.
__init__
()
self
.
_
request
=
request
self
.
request
=
request
try
:
try
:
return
self
.
_handle_request
(
request
,
*
args
,
**
kwargs
)
return
self
.
_handle_request
(
request
,
*
args
,
**
kwargs
)
except
:
except
:
...
@@ -76,7 +76,7 @@ class Resource(object):
...
@@ -76,7 +76,7 @@ class Resource(object):
TODO: Add SITEMAP option.
TODO: Add SITEMAP option.
Provided for convienience."""
Provided for convienience."""
return
self
.
_
request
.
build_absolute_uri
(
reverse
(
view
,
*
args
,
**
kwargs
))
return
self
.
request
.
build_absolute_uri
(
reverse
(
view
,
*
args
,
**
kwargs
))
def
make_absolute
(
self
,
uri
):
def
make_absolute
(
self
,
uri
):
...
@@ -84,7 +84,7 @@ class Resource(object):
...
@@ -84,7 +84,7 @@ class Resource(object):
TODO: Add SITEMAP option.
TODO: Add SITEMAP option.
Provided for convienience."""
Provided for convienience."""
return
self
.
_
request
.
build_absolute_uri
(
uri
)
return
self
.
request
.
build_absolute_uri
(
uri
)
def
read
(
self
,
headers
=
{},
*
args
,
**
kwargs
):
def
read
(
self
,
headers
=
{},
*
args
,
**
kwargs
):
...
@@ -137,36 +137,41 @@ class Resource(object):
...
@@ -137,36 +137,41 @@ class Resource(object):
def
determine_form
(
self
,
input_data
=
None
,
return_data
=
Non
e
):
def
determine_form
(
self
,
data
=
None
,
is_response
=
Fals
e
):
"""Optionally return a Django Form instance, which may be used for validation
"""Optionally return a Django Form instance, which may be used for validation
and/or rendered by an HTML/XHTML emitter.
and/or rendered by an HTML/XHTML emitter.
The input_data or return_data arguments can be used to bind the form either to the deserialized input,
If data is not None the form will be bound to data. is_response indicates if data should be
or to a return object.
treated as the input data (bind to client input) or the response data (bind to an existing object).
"""
"""
if
self
.
form
:
if
self
.
form
:
if
input_data
:
if
data
:
return
self
.
form
(
input_data
)
return
self
.
form
(
data
)
elif
return_data
:
return
self
.
form
(
return_data
)
else
:
else
:
return
self
.
form
()
return
self
.
form
()
return
None
return
None
def
cleanup_request
(
self
,
data
,
form
=
None
):
def
cleanup_request
(
self
,
data
):
"""Perform any resource-specific data deserialization and/or validation
"""Perform any resource-specific data deserialization and/or validation
after the initial HTTP content-type deserialization has taken place.
after the initial HTTP content-type deserialization has taken place.
Optionally this may use a Django Form which will have been bound to the data,
By default this uses form validation to filter the basic input into the required types."""
rather than using the data directly.
if
self
.
form
is
None
:
"""
return
data
return
data
if
not
self
.
form
.
is_valid
():
details
=
dict
((
key
,
map
(
unicode
,
val
))
for
(
key
,
val
)
in
self
.
form
.
errors
.
iteritems
())
raise
ResourceException
(
STATUS_400_BAD_REQUEST
,
{
'detail'
:
details
})
return
self
.
form
.
cleaned_data
def
cleanup_response
(
self
,
data
):
def
cleanup_response
(
self
,
data
):
"""Perform any resource-specific data filtering prior to the standard HTTP
"""Perform any resource-specific data filtering prior to the standard HTTP
content-type serialization."""
content-type serialization.
Eg filter complex objects that cannot be serialized by json/xml/etc into basic objects that can."""
return
data
return
data
...
@@ -247,53 +252,57 @@ class Resource(object):
...
@@ -247,53 +252,57 @@ class Resource(object):
4. cleanup the response data
4. cleanup the response data
5. serialize response data into response content, using standard HTTP content negotiation
5. serialize response data into response content, using standard HTTP content negotiation
"""
"""
method
=
self
.
determine_method
(
request
)
emitter
=
None
emitter
=
None
form
=
None
# We make these attributes to allow for a certain amount of munging,
# eg The HTML emitter needs to render this information
self
.
method
=
self
.
determine_method
(
request
)
self
.
form
=
None
self
.
resp_status
=
None
self
.
resp_content
=
None
self
.
resp_headers
=
{}
try
:
try
:
# Before we attempt anything else determine what format to emit our response data with.
# Before we attempt anything else determine what format to emit our response data with.
mimetype
,
emitter
=
self
.
determine_emitter
(
request
)
mimetype
,
emitter
=
self
.
determine_emitter
(
request
)
# Ensure the requested operation is permitted on this resource
# Ensure the requested operation is permitted on this resource
self
.
check_method_allowed
(
method
)
self
.
check_method_allowed
(
self
.
method
)
# Get the appropriate create/read/update/delete function
# Get the appropriate create/read/update/delete function
func
=
getattr
(
self
,
self
.
CALLMAP
.
get
(
method
,
''
))
func
=
getattr
(
self
,
self
.
CALLMAP
.
get
(
self
.
method
,
''
))
# Either generate the response data, deserializing and validating any request data
# Either generate the response data, deserializing and validating any request data
if
method
in
(
'PUT'
,
'POST'
):
if
self
.
method
in
(
'PUT'
,
'POST'
):
parser
=
self
.
determine_parser
(
request
)
parser
=
self
.
determine_parser
(
request
)
data
=
parser
(
self
,
request
)
.
parse
(
request
.
raw_post_data
)
data
=
parser
(
self
)
.
parse
(
request
.
raw_post_data
)
form
=
self
.
determine_form
(
input_data
=
data
)
self
.
form
=
self
.
determine_form
(
data
)
data
=
self
.
cleanup_request
(
data
,
form
)
data
=
self
.
cleanup_request
(
data
)
(
s
tatus
,
ret
,
headers
)
=
func
(
data
,
request
.
META
,
*
args
,
**
kwargs
)
(
s
elf
.
resp_status
,
ret
,
self
.
resp_
headers
)
=
func
(
data
,
request
.
META
,
*
args
,
**
kwargs
)
else
:
else
:
(
s
tatus
,
ret
,
headers
)
=
func
(
request
.
META
,
*
args
,
**
kwargs
)
(
s
elf
.
resp_status
,
ret
,
self
.
resp_
headers
)
=
func
(
request
.
META
,
*
args
,
**
kwargs
)
form
=
self
.
determine_form
(
return_data
=
ret
)
self
.
form
=
self
.
determine_form
(
ret
,
is_response
=
True
)
except
ResourceException
,
exc
:
except
ResourceException
,
exc
:
(
status
,
ret
,
headers
)
=
(
exc
.
status
,
exc
.
content
,
exc
.
headers
)
(
self
.
resp_status
,
ret
,
self
.
resp_headers
)
=
(
exc
.
status
,
exc
.
content
,
exc
.
headers
)
if
emitter
is
None
:
mimetype
,
emitter
=
self
.
emitters
[
0
]
if
self
.
form
is
None
:
self
.
form
=
self
.
determine_form
()
# Use a default emitter if request failed without being able to determine an acceptable emitter
if
emitter
is
None
:
mimetype
,
emitter
=
self
.
emitters
[
0
]
# Create an unbound form if one has not yet been created
if
form
is
None
:
form
=
self
.
determine_form
()
# Always add the allow header
# Always add the allow header
headers
[
'Allow'
]
=
', '
.
join
([
self
.
REVERSE_CALLMAP
[
operation
]
for
operation
in
self
.
allowed_operations
])
self
.
resp_
headers
[
'Allow'
]
=
', '
.
join
([
self
.
REVERSE_CALLMAP
[
operation
]
for
operation
in
self
.
allowed_operations
])
# Serialize the response content
# Serialize the response content
ret
=
self
.
cleanup_response
(
ret
)
ret
=
self
.
cleanup_response
(
ret
)
content
=
emitter
(
self
,
request
,
status
,
headers
,
form
)
.
emit
(
ret
)
content
=
emitter
(
self
)
.
emit
(
ret
)
# Build the HTTP Response
# Build the HTTP Response
resp
=
HttpResponse
(
content
,
mimetype
=
mimetype
,
status
=
status
)
resp
=
HttpResponse
(
content
,
mimetype
=
mimetype
,
status
=
s
elf
.
resp_s
tatus
)
for
(
key
,
val
)
in
headers
.
items
():
for
(
key
,
val
)
in
self
.
resp_
headers
.
items
():
resp
[
key
]
=
val
resp
[
key
]
=
val
return
resp
return
resp
...
@@ -313,10 +322,10 @@ class ModelResource(Resource):
...
@@ -313,10 +322,10 @@ class ModelResource(Resource):
fields
=
None
fields
=
None
form_fields
=
None
form_fields
=
None
def
determine_form
(
self
,
input_data
=
None
,
return_data
=
Non
e
):
def
determine_form
(
self
,
data
=
None
,
is_response
=
Fals
e
):
"""Return a form that may be used in validation and/or rendering an html emitter"""
"""Return a form that may be used in validation and/or rendering an html emitter"""
if
self
.
form
:
if
self
.
form
:
return
s
elf
.
form
return
s
uper
(
self
.
__class__
,
self
)
.
determine_form
(
data
,
is_response
=
is_response
)
elif
self
.
model
:
elif
self
.
model
:
class
NewModelForm
(
ModelForm
):
class
NewModelForm
(
ModelForm
):
...
@@ -324,26 +333,17 @@ class ModelResource(Resource):
...
@@ -324,26 +333,17 @@ class ModelResource(Resource):
model
=
self
.
model
model
=
self
.
model
fields
=
self
.
form_fields
if
self
.
form_fields
else
None
#self.fields
fields
=
self
.
form_fields
if
self
.
form_fields
else
None
#self.fields
if
input_data
:
if
data
and
not
is_response
:
return
NewModelForm
(
input_
data
)
return
NewModelForm
(
data
)
elif
return_data
:
elif
data
and
is_response
:
return
NewModelForm
(
instance
=
return_
data
)
return
NewModelForm
(
instance
=
data
)
else
:
else
:
return
NewModelForm
()
return
NewModelForm
()
else
:
else
:
return
None
return
None
def
cleanup_request
(
self
,
data
,
form
=
None
):
"""Filter data into form-cleaned data, performing validation and type coercion."""
if
form
is
None
:
return
data
if
not
form
.
is_valid
():
details
=
dict
((
key
,
map
(
unicode
,
val
))
for
(
key
,
val
)
in
form
.
errors
.
iteritems
())
raise
ResourceException
(
STATUS_400_BAD_REQUEST
,
{
'detail'
:
details
})
return
form
.
cleaned_data
def
cleanup_response
(
self
,
data
):
def
cleanup_response
(
self
,
data
):
"""
"""
...
@@ -614,7 +614,7 @@ class ModelResource(Resource):
...
@@ -614,7 +614,7 @@ class ModelResource(Resource):
try
:
try
:
instance
=
self
.
model
.
objects
.
get
(
**
kwargs
)
instance
=
self
.
model
.
objects
.
get
(
**
kwargs
)
except
self
.
model
.
DoesNotExist
:
except
self
.
model
.
DoesNotExist
:
return
(
404
,
''
,
{})
return
(
404
,
None
,
{})
return
(
200
,
instance
,
{})
return
(
200
,
instance
,
{})
...
@@ -633,13 +633,14 @@ class ModelResource(Resource):
...
@@ -633,13 +633,14 @@ class ModelResource(Resource):
def
delete
(
self
,
headers
=
{},
*
args
,
**
kwargs
):
def
delete
(
self
,
headers
=
{},
*
args
,
**
kwargs
):
instance
=
self
.
model
.
objects
.
get
(
**
kwargs
)
instance
=
self
.
model
.
objects
.
get
(
**
kwargs
)
instance
.
delete
()
instance
.
delete
()
return
(
204
,
''
,
{})
return
(
204
,
None
,
{})
class
QueryModelResource
(
ModelResource
):
class
QueryModelResource
(
ModelResource
):
allowed_methods
=
(
'read'
,)
allowed_methods
=
(
'read'
,)
def
determine_form
(
self
,
input_data
=
None
,
return_data
=
Non
e
):
def
determine_form
(
self
,
data
=
None
,
is_response
=
Fals
e
):
return
None
return
None
def
read
(
self
,
headers
=
{},
*
args
,
**
kwargs
):
def
read
(
self
,
headers
=
{},
*
args
,
**
kwargs
):
...
...
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