diff options
| author | Tom Christie | 2012-02-17 09:19:13 +0000 |
|---|---|---|
| committer | Tom Christie | 2012-02-17 09:19:13 +0000 |
| commit | fbf76c87affc88f04bb0d0acaecc6af6442ba921 (patch) | |
| tree | 5a75cbb061829694c4f714ae0e8413c584131739 /djangorestframework/views.py | |
| parent | 426493a78f3003fdba39053b6af23b93b312a777 (diff) | |
| parent | c04cb5145c4398cfac090ca7eef032296a04446f (diff) | |
| download | django-rest-framework-fbf76c87affc88f04bb0d0acaecc6af6442ba921.tar.bz2 | |
Merge git://github.com/sebpiq/django-rest-framework into develop
Diffstat (limited to 'djangorestframework/views.py')
| -rw-r--r-- | djangorestframework/views.py | 89 |
1 files changed, 44 insertions, 45 deletions
diff --git a/djangorestframework/views.py b/djangorestframework/views.py index 32d2437c..93e2d3a3 100644 --- a/djangorestframework/views.py +++ b/djangorestframework/views.py @@ -13,8 +13,9 @@ from django.utils.safestring import mark_safe from django.views.decorators.csrf import csrf_exempt from djangorestframework.compat import View as DjangoView, apply_markdown -from djangorestframework.response import Response, ErrorResponse +from djangorestframework.response import Response, ImmediateResponse from djangorestframework.mixins import * +from djangorestframework.utils import allowed_methods from djangorestframework import resources, renderers, parsers, authentication, permissions, status @@ -81,14 +82,14 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): or `None` to use default behaviour. """ - renderers = renderers.DEFAULT_RENDERERS + renderer_classes = renderers.DEFAULT_RENDERERS """ - List of renderers the resource can serialize the response with, ordered by preference. + List of renderer classes the resource can serialize the response with, ordered by preference. """ - parsers = parsers.DEFAULT_PARSERS + parser_classes = parsers.DEFAULT_PARSERS """ - List of parsers the resource can parse the request with. + List of parser classes the resource can parse the request with. """ authentication = (authentication.UserLoggedInAuthentication, @@ -118,7 +119,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): """ Return the list of allowed HTTP methods, uppercased. """ - return [method.upper() for method in self.http_method_names if hasattr(self, method)] + return allowed_methods(self) def get_name(self): """ @@ -172,12 +173,14 @@ 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 ErrorResponse(status.HTTP_405_METHOD_NOT_ALLOWED, - {'detail': 'Method \'%s\' not allowed on this resource.' % self.method}) + raise ImmediateResponse( + {'detail': 'Method \'%s\' not allowed on this resource.' % request.method}, + status=status.HTTP_405_METHOD_NOT_ALLOWED) def initial(self, request, *args, **kargs): """ - Hook for any code that needs to run prior to anything else. + Returns an `HttpRequest`. This method is a hook for any code that needs to run + prior to anything else. Required if you want to do things like set `request.upload_handlers` before the authentication and dispatch handling is run. """ @@ -187,28 +190,22 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): if not (self.orig_prefix.startswith('http:') or self.orig_prefix.startswith('https:')): prefix = '%s://%s' % (request.is_secure() and 'https' or 'http', request.get_host()) set_script_prefix(prefix + self.orig_prefix) + return request def final(self, request, response, *args, **kargs): """ - Hook for any code that needs to run after everything else in the view. + Returns an `HttpResponse`. This method is a hook for any code that needs to run + after everything else in the view. """ # Restore script_prefix. set_script_prefix(self.orig_prefix) # Always add these headers. - response.headers['Allow'] = ', '.join(self.allowed_methods) + response['Allow'] = ', '.join(allowed_methods(self)) # sample to allow caching using Vary http header - response.headers['Vary'] = 'Authenticate, Accept' + response['Vary'] = 'Authenticate, Accept' - # merge with headers possibly set at some point in the view - response.headers.update(self.headers) - return self.render(response) - - def add_header(self, field, value): - """ - Add *field* and *value* to the :attr:`headers` attribute of the :class:`View` class. - """ - self.headers[field] = value + return response # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. @@ -217,42 +214,47 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): self.request = request self.args = args self.kwargs = kwargs - self.headers = {} try: - self.initial(request, *args, **kwargs) + # Get a custom request, built form the original request instance + self.request = request = self.create_request(request) + + # `initial` is the opportunity to temper with the request, + # even completely replace it. + self.request = request = self.initial(request, *args, **kwargs) # Authenticate and check request has the relevant permissions self._check_permissions() # Get the appropriate handler method - if self.method.lower() in self.http_method_names: - handler = getattr(self, self.method.lower(), self.http_method_not_allowed) + if request.method.lower() in self.http_method_names: + handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed + + # TODO: should we enforce HttpResponse, like Django does ? + response = handler(request, *args, **kwargs) - response_obj = handler(request, *args, **kwargs) - - # Allow return value to be either HttpResponse, Response, or an object, or None - if isinstance(response_obj, HttpResponse): - return response_obj - elif isinstance(response_obj, Response): - response = response_obj - elif response_obj is not None: - response = Response(status.HTTP_200_OK, response_obj) - else: - response = Response(status.HTTP_204_NO_CONTENT) + # Prepare response for the response cycle. + self.response = response = self.prepare_response(response) # Pre-serialize filtering (eg filter complex objects into natively serializable types) - response.cleaned_content = self.filter_response(response.raw_content) + # TODO: ugly hack to handle both HttpResponse and Response. + if hasattr(response, 'raw_content'): + response.raw_content = self.filter_response(response.raw_content) + else: + response.content = self.filter_response(response.content) - except ErrorResponse, exc: - response = exc.response + except ImmediateResponse, response: + # Prepare response for the response cycle. + self.response = response = self.prepare_response(response) + # `final` is the last opportunity to temper with the response, or even + # completely replace it. return self.final(request, response, *args, **kwargs) def options(self, request, *args, **kwargs): - response_obj = { + content = { 'name': self.get_name(), 'description': self.get_description(), 'renders': self._rendered_media_types, @@ -263,11 +265,8 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): field_name_types = {} for name, field in form.fields.iteritems(): field_name_types[name] = field.__class__.__name__ - response_obj['fields'] = field_name_types - # Note 'ErrorResponse' is misleading, it's just any response - # that should be rendered and returned immediately, without any - # response filtering. - raise ErrorResponse(status.HTTP_200_OK, response_obj) + content['fields'] = field_name_types + raise ImmediateResponse(content, status=status.HTTP_200_OK) class ModelView(View): |
