aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--djangorestframework/tests/views.py16
-rw-r--r--djangorestframework/views.py46
2 files changed, 38 insertions, 24 deletions
diff --git a/djangorestframework/tests/views.py b/djangorestframework/tests/views.py
index e03f6615..ab5d75d6 100644
--- a/djangorestframework/tests/views.py
+++ b/djangorestframework/tests/views.py
@@ -1,4 +1,5 @@
from django.conf.urls.defaults import patterns, url
+from django.http import HttpResponse
from django.test import TestCase
from django.test import Client
from django import forms
@@ -16,6 +17,13 @@ class MockView(View):
"""This is a basic mock view"""
pass
+
+class MockViewFinal(View):
+ """View with final() override"""
+
+ def final(self, request, response, *args, **kwargs):
+ return HttpResponse('{"test": "passed"}', content_type="application/json")
+
class ResourceMockView(View):
"""This is a resource-based mock view"""
@@ -43,6 +51,7 @@ urlpatterns = patterns('djangorestframework.utils.staticviews',
url(r'^accounts/login$', 'api_login'),
url(r'^accounts/logout$', 'api_logout'),
url(r'^mock/$', MockView.as_view()),
+ url(r'^mock/final/$', MockViewFinal.as_view()),
url(r'^resourcemock/$', ResourceMockView.as_view()),
url(r'^model/$', ListOrCreateModelView.as_view(resource=MockResource)),
url(r'^model/(?P<pk>[^/]+)/$', InstanceModelView.as_view(resource=MockResource)),
@@ -52,6 +61,13 @@ class BaseViewTests(TestCase):
"""Test the base view class of djangorestframework"""
urls = 'djangorestframework.tests.views'
+ def test_view_call_final(self):
+ response = self.client.options('/mock/final/')
+ self.assertEqual(response['Content-Type'].split(';')[0], "application/json")
+ parser = JSONParser(None)
+ (data, files) = parser.parse(StringIO(response.content))
+ self.assertEqual(data['test'], 'passed')
+
def test_options_method_simple_view(self):
response = self.client.options('/mock/')
self._verify_options_response(response,
diff --git a/djangorestframework/views.py b/djangorestframework/views.py
index 4606e50b..eb742743 100644
--- a/djangorestframework/views.py
+++ b/djangorestframework/views.py
@@ -59,7 +59,6 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
"""
permissions = ( permissions.FullAnonAccess, )
-
@classmethod
def as_view(cls, **initkwargs):
"""
@@ -71,7 +70,6 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
view.cls_instance = cls(**initkwargs)
return view
-
@property
def allowed_methods(self):
"""
@@ -79,7 +77,6 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
"""
return [method.upper() for method in self.http_method_names if hasattr(self, method)]
-
def http_method_not_allowed(self, request, *args, **kwargs):
"""
Return an HTTP 405 error if an operation is called which does not have a handler method.
@@ -87,15 +84,34 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
raise ErrorResponse(status.HTTP_405_METHOD_NOT_ALLOWED,
{'detail': 'Method \'%s\' not allowed on this resource.' % self.method})
-
def initial(self, request, *args, **kargs):
"""
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.
"""
- pass
+ # Calls to 'reverse' will not be fully qualified unless we set the
+ # scheme/host/port here.
+ self.orig_prefix = get_script_prefix()
+ 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)
+ def final(self, request, response, *args, **kargs):
+ """
+ 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)
+ # sample to allow caching using Vary http header
+ response.headers['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):
"""
@@ -113,12 +129,6 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
self.kwargs = kwargs
self.headers = {}
- # Calls to 'reverse' will not be fully qualified unless we set the scheme/host/port here.
- orig_prefix = get_script_prefix()
- if not (orig_prefix.startswith('http:') or orig_prefix.startswith('https:')):
- prefix = '%s://%s' % (request.is_secure() and 'https' or 'http', request.get_host())
- set_script_prefix(prefix + orig_prefix)
-
try:
self.initial(request, *args, **kwargs)
@@ -154,19 +164,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
except ErrorResponse, exc:
response = exc.response
- # Always add these headers.
- #
- # TODO - this isn't actually the correct way to set the vary header,
- # also it's currently sub-optimal for HTTP caching - need to sort that out.
- response.headers['Allow'] = ', '.join(self.allowed_methods)
- response.headers['Vary'] = 'Authenticate, Accept'
-
- # merge with headers possibly set at some point in the view
- response.headers.update(self.headers)
-
- set_script_prefix(orig_prefix)
-
- return self.render(response)
+ return self.final(request, response, *args, **kwargs)
def options(self, request, *args, **kwargs):
response_obj = {