aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework/views.py
diff options
context:
space:
mode:
authorTom Christie2012-02-17 09:19:13 +0000
committerTom Christie2012-02-17 09:19:13 +0000
commitfbf76c87affc88f04bb0d0acaecc6af6442ba921 (patch)
tree5a75cbb061829694c4f714ae0e8413c584131739 /djangorestframework/views.py
parent426493a78f3003fdba39053b6af23b93b312a777 (diff)
parentc04cb5145c4398cfac090ca7eef032296a04446f (diff)
downloaddjango-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.py89
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):