diff options
Diffstat (limited to 'djangorestframework/resource.py')
| -rw-r--r-- | djangorestframework/resource.py | 61 |
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' |
