aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework/resource.py
diff options
context:
space:
mode:
authortom christie tom@tomchristie.com2011-04-02 16:32:37 +0100
committertom christie tom@tomchristie.com2011-04-02 16:32:37 +0100
commit4687db680cda52e9836743940e4cf7279b307294 (patch)
tree23b9b22eee3c08f6de09295b3c6630f5fb0730fa /djangorestframework/resource.py
parent8845b281fe9aafbc9f9b2a283fafbde9787f4734 (diff)
downloaddjango-rest-framework-4687db680cda52e9836743940e4cf7279b307294.tar.bz2
Refactor to use self.CONTENT to access request body. Get file upload working
Diffstat (limited to 'djangorestframework/resource.py')
-rw-r--r--djangorestframework/resource.py61
1 files changed, 22 insertions, 39 deletions
diff --git a/djangorestframework/resource.py b/djangorestframework/resource.py
index 15c1d7c8..80e5df2a 100644
--- a/djangorestframework/resource.py
+++ b/djangorestframework/resource.py
@@ -6,47 +6,42 @@ from djangorestframework.emitters import EmitterMixin
from djangorestframework.parsers import ParserMixin
from djangorestframework.authenticators import AuthenticatorMixin
from djangorestframework.validators import FormValidatorMixin
-from djangorestframework.content import OverloadedContentMixin
-from djangorestframework.methods import OverloadedPOSTMethodMixin
from djangorestframework.response import Response, ResponseException
+from djangorestframework.request import RequestMixin
from djangorestframework import emitters, parsers, authenticators, status
-import re
# TODO: Figure how out references and named urls need to work nicely
# TODO: POST on existing 404 URL, PUT on existing 404 URL
#
# NEXT: Exceptions on func() -> 500, tracebacks emitted if settings.DEBUG
-#
__all__ = ['Resource']
-
-
-class Resource(EmitterMixin, ParserMixin, AuthenticatorMixin, FormValidatorMixin,
- OverloadedContentMixin, OverloadedPOSTMethodMixin, View):
+class Resource(EmitterMixin, ParserMixin, AuthenticatorMixin, FormValidatorMixin, RequestMixin, View):
"""Handles incoming requests and maps them to REST operations,
performing authentication, input deserialization, input validation, output serialization."""
# List of RESTful operations which may be performed on this resource.
+ # These are going to get dropped at some point, the allowable methods will be defined simply by
+ # which methods are present on the request (in the same way as Django's generic View)
allowed_methods = ('GET',)
anon_allowed_methods = ()
- # List of emitters the resource can serialize the response with, ordered by preference
+ # List of emitters the resource can serialize the response with, ordered by preference.
emitters = ( emitters.JSONEmitter,
emitters.DocumentingHTMLEmitter,
emitters.DocumentingXHTMLEmitter,
emitters.DocumentingPlainTextEmitter,
emitters.XMLEmitter )
- # List of content-types the resource can read from
+ # List of parsers the resource can parse the request with.
parsers = ( parsers.JSONParser,
- parsers.XMLParser,
parsers.FormParser,
parsers.MultipartParser )
- # List of all authenticating methods to attempt
+ # List of all authenticating methods to attempt.
authenticators = ( authenticators.UserLoggedInAuthenticator,
authenticators.BasicAuthenticator )
@@ -63,12 +58,6 @@ class Resource(EmitterMixin, ParserMixin, AuthenticatorMixin, FormValidatorMixin
callmap = { 'GET': 'get', 'POST': 'post',
'PUT': 'put', 'DELETE': 'delete' }
-
- # Some reserved parameters to allow us to use standard HTML forms with our resource
- # Override any/all of these with None to disable them, or override them with another value to rename them.
- CSRF_PARAM = 'csrfmiddlewaretoken' # Django's CSRF token used in form params
-
-
def get(self, request, auth, *args, **kwargs):
"""Must be subclassed to be implemented."""
self.not_implemented('GET')
@@ -137,24 +126,14 @@ class Resource(EmitterMixin, ParserMixin, AuthenticatorMixin, FormValidatorMixin
4. cleanup the response data
5. serialize response data into response content, using standard HTTP content negotiation
"""
-
+
self.request = request
# Calls to 'reverse' will not be fully qualified unless we set the scheme/host/port here.
prefix = '%s://%s' % (request.is_secure() and 'https' or 'http', request.get_host())
set_script_prefix(prefix)
- # These sets are determined now so that overridding classes can modify the various parameter names,
- # or set them to None to disable them.
- self.RESERVED_FORM_PARAMS = set((self.METHOD_PARAM, self.CONTENTTYPE_PARAM, self.CONTENT_PARAM, self.CSRF_PARAM))
- self.RESERVED_QUERY_PARAMS = set((self.ACCEPT_QUERY_PARAM))
- self.RESERVED_FORM_PARAMS.discard(None)
- self.RESERVED_QUERY_PARAMS.discard(None)
-
- method = self.determine_method(request)
-
try:
-
# Authenticate the request, and store any context so that the resource operations can
# do more fine grained authentication if required.
#
@@ -163,19 +142,21 @@ class Resource(EmitterMixin, ParserMixin, AuthenticatorMixin, FormValidatorMixin
# has been signed against a particular set of permissions)
auth_context = self.authenticate(request)
+ # If using a form POST with '_method'/'_content'/'_content_type' overrides, then alter
+ # self.method, self.content_type, self.CONTENT appropriately.
+ self.perform_form_overloading()
+
# Ensure the requested operation is permitted on this resource
- self.check_method_allowed(method, auth_context)
+ self.check_method_allowed(self.method, auth_context)
# Get the appropriate create/read/update/delete function
- func = getattr(self, self.callmap.get(method, None))
+ func = getattr(self, self.callmap.get(self.method, None))
# Either generate the response data, deserializing and validating any request data
- # TODO: Add support for message bodys on other HTTP methods, as it is valid (although non-conventional).
- if method in ('PUT', 'POST'):
- (content_type, content) = self.determine_content(request)
- parser_content = self.parse(content_type, content)
- cleaned_content = self.validate(parser_content)
- response_obj = func(request, auth_context, cleaned_content, *args, **kwargs)
+ # TODO: This is going to change to: func(request, *args, **kwargs)
+ # That'll work out now that we have the lazily evaluated self.CONTENT property.
+ if self.method in ('PUT', 'POST'):
+ response_obj = func(request, auth_context, self.CONTENT, *args, **kwargs)
else:
response_obj = func(request, auth_context, *args, **kwargs)
@@ -191,11 +172,13 @@ class Resource(EmitterMixin, ParserMixin, AuthenticatorMixin, FormValidatorMixin
# Pre-serialize filtering (eg filter complex objects into natively serializable types)
response.cleaned_content = self.cleanup_response(response.raw_content)
-
except ResponseException, exc:
response = exc.response
- # Always add these headers
+ # Always add these headers.
+ #
+ # TODO - this isn't actually the correct way to set the vary header,
+ # also it's currently sub-obtimal for HTTP caching - need to sort that out.
response.headers['Allow'] = ', '.join(self.allowed_methods)
response.headers['Vary'] = 'Authenticate, Accept'