diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py index 57b855957..516a0f4b5 100644 --- a/djangorestframework/mixins.py +++ b/djangorestframework/mixins.py @@ -43,7 +43,6 @@ class RequestMixin(object): parser_classes = () """ The set of parsers that the view can handle. - Should be a tuple/list of classes as described in the :mod:`parsers` module. """ @@ -54,22 +53,18 @@ class RequestMixin(object): def get_parsers(self): """ - Instantiates and returns the list of parsers that will be used by the request - to parse its content. + Instantiates and returns the list of parsers the request will use. """ - if not hasattr(self, '_parsers'): - self._parsers = [p(self) for p in self.parser_classes] - return self._parsers + return [p(self) for p in self.parser_classes] - def prepare_request(self, request): + def create_request(self, request): """ - Prepares the request cycle. Returns an instance of :class:`request.Request`, - wrapping the original request object. + Creates and returns an instance of :class:`request.Request`. + This new instance wraps the `request` passed as a parameter, and use the + parsers set on the view. """ parsers = self.get_parsers() - request = self.request_class(request, parsers=parsers) - self.request = request - return request + return self.request_class(request, parsers=parsers) @property def _parsed_media_types(self): @@ -89,38 +84,29 @@ class ResponseMixin(object): renderer_classes = () """ The set of response renderers that the view can handle. - Should be a tuple/list of classes as described in the :mod:`renderers` module. """ def get_renderers(self): """ - Instantiates and returns the list of renderers that will be used to render - the response. + Instantiates and returns the list of renderers the response will use. """ - if not hasattr(self, '_renderers'): - self._renderers = [r(self) for r in self.renderer_classes] - return self._renderers + return [r(self) for r in self.renderer_classes] def prepare_response(self, response): """ - Prepares and returns `response`. + Prepares and returns `response`. This has no effect if the response is not an instance of :class:`response.Response`. """ if hasattr(response, 'request') and response.request is None: response.request = self.request - # Always add these headers. - response['Allow'] = ', '.join(allowed_methods(self)) - # sample to allow caching using Vary http header - response['Vary'] = 'Authenticate, Accept' - # merge with headers possibly set at some point in the view + # set all the cached headers for name, value in self.headers.items(): response[name] = value # set the views renderers on the response response.renderers = self.get_renderers() - self.response = response return response @property @@ -571,12 +557,12 @@ class PaginatorMixin(object): page_num = int(self.request.GET.get('page', '1')) except ValueError: raise ImmediateResponse( - content={'detail': 'That page contains no results'}, + {'detail': 'That page contains no results'}, status=status.HTTP_404_NOT_FOUND) if page_num not in paginator.page_range: raise ImmediateResponse( - content={'detail': 'That page contains no results'}, + {'detail': 'That page contains no results'}, status=status.HTTP_404_NOT_FOUND) page = paginator.page(page_num) diff --git a/djangorestframework/parsers.py b/djangorestframework/parsers.py index c041d7ce4..d41e07e8b 100644 --- a/djangorestframework/parsers.py +++ b/djangorestframework/parsers.py @@ -89,7 +89,7 @@ class JSONParser(BaseParser): return (json.load(stream), None) except ValueError, exc: raise ImmediateResponse( - content={'detail': 'JSON parse error - %s' % unicode(exc)}, + {'detail': 'JSON parse error - %s' % unicode(exc)}, status=status.HTTP_400_BAD_REQUEST) @@ -112,7 +112,7 @@ if yaml: return (yaml.safe_load(stream), None) except ValueError, exc: raise ImmediateResponse( - content={'detail': 'YAML parse error - %s' % unicode(exc)}, + {'detail': 'YAML parse error - %s' % unicode(exc)}, status=status.HTTP_400_BAD_REQUEST) else: YAMLParser = None @@ -172,7 +172,7 @@ class MultiPartParser(BaseParser): django_parser = DjangoMultiPartParser(self.view.request.META, stream, upload_handlers) except MultiPartParserError, exc: raise ImmediateResponse( - content={'detail': 'multipart parse error - %s' % unicode(exc)}, + {'detail': 'multipart parse error - %s' % unicode(exc)}, status=status.HTTP_400_BAD_REQUEST) return django_parser.parse() diff --git a/djangorestframework/permissions.py b/djangorestframework/permissions.py index 4ddc35cb9..aa4cd631d 100644 --- a/djangorestframework/permissions.py +++ b/djangorestframework/permissions.py @@ -22,12 +22,12 @@ __all__ = ( _403_FORBIDDEN_RESPONSE = ImmediateResponse( - content={'detail': 'You do not have permission to access this resource. ' + + {'detail': 'You do not have permission to access this resource. ' + 'You may need to login or otherwise authenticate the request.'}, status=status.HTTP_403_FORBIDDEN) _503_SERVICE_UNAVAILABLE = ImmediateResponse( - content={'detail': 'request was throttled'}, + {'detail': 'request was throttled'}, status=status.HTTP_503_SERVICE_UNAVAILABLE) diff --git a/djangorestframework/request.py b/djangorestframework/request.py index 8cf95f185..d4ea1e010 100644 --- a/djangorestframework/request.py +++ b/djangorestframework/request.py @@ -166,9 +166,9 @@ class Request(object): if parser.can_handle_request(content_type): return parser.parse(stream) - raise ImmediateResponse(content={'error': - 'Unsupported media type in request \'%s\'.' % content_type}, - status=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE) + raise ImmediateResponse({ + 'error': 'Unsupported media type in request \'%s\'.' % content_type}, + status=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE) @property def _parsed_media_types(self): diff --git a/djangorestframework/resources.py b/djangorestframework/resources.py index f478bd521..15b3579de 100644 --- a/djangorestframework/resources.py +++ b/djangorestframework/resources.py @@ -174,7 +174,7 @@ class FormResource(Resource): detail[u'field_errors'] = field_errors # Return HTTP 400 response (BAD REQUEST) - raise ImmediateResponse(content=detail, status=400) + raise ImmediateResponse(detail, status=400) def get_form_class(self, method=None): """ diff --git a/djangorestframework/response.py b/djangorestframework/response.py index 29fffed30..c5fdccbcd 100644 --- a/djangorestframework/response.py +++ b/djangorestframework/response.py @@ -125,7 +125,7 @@ class Response(SimpleTemplateResponse): return renderer, media_type # No acceptable renderers were found - raise ImmediateResponse(content={'detail': 'Could not satisfy the client\'s Accept header', + raise ImmediateResponse({'detail': 'Could not satisfy the client\'s Accept header', 'available_types': self._rendered_media_types}, status=status.HTTP_406_NOT_ACCEPTABLE, renderers=self.renderers) diff --git a/djangorestframework/views.py b/djangorestframework/views.py index 5bba6b4eb..93e2d3a3c 100644 --- a/djangorestframework/views.py +++ b/djangorestframework/views.py @@ -173,7 +173,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): """ Return an HTTP 405 error if an operation is called which does not have a handler method. """ - raise ImmediateResponse(content= + raise ImmediateResponse( {'detail': 'Method \'%s\' not allowed on this resource.' % request.method}, status=status.HTTP_405_METHOD_NOT_ALLOWED) @@ -199,6 +199,12 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): """ # Restore script_prefix. set_script_prefix(self.orig_prefix) + + # Always add these headers. + response['Allow'] = ', '.join(allowed_methods(self)) + # sample to allow caching using Vary http header + response['Vary'] = 'Authenticate, Accept' + return response # Note: session based authentication is explicitly CSRF validated, @@ -211,7 +217,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): try: # Get a custom request, built form the original request instance - request = self.prepare_request(request) + self.request = request = self.create_request(request) # `initial` is the opportunity to temper with the request, # even completely replace it. @@ -230,7 +236,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): response = handler(request, *args, **kwargs) # Prepare response for the response cycle. - response = self.prepare_response(response) + self.response = response = self.prepare_response(response) # Pre-serialize filtering (eg filter complex objects into natively serializable types) # TODO: ugly hack to handle both HttpResponse and Response. @@ -241,7 +247,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): except ImmediateResponse, response: # Prepare response for the response cycle. - self.prepare_response(response) + self.response = response = self.prepare_response(response) # `final` is the last opportunity to temper with the response, or even # completely replace it. @@ -260,10 +266,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): for name, field in form.fields.iteritems(): field_name_types[name] = field.__class__.__name__ content['fields'] = field_name_types - # Note 'ImmediateResponse' is misleading, it's just any response - # that should be rendered and returned immediately, without any - # response filtering. - raise ImmediateResponse(content=content, status=status.HTTP_200_OK) + raise ImmediateResponse(content, status=status.HTTP_200_OK) class ModelView(View):