aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework
diff options
context:
space:
mode:
authorTom Christie2011-05-24 10:27:24 +0100
committerTom Christie2011-05-24 10:27:24 +0100
commit370274f5640d55ef71422f7a2440710a43ff900e (patch)
tree2b970d3e1ad6d283050139bfe7a914bf10586963 /djangorestframework
parent698df527a3b80edbf4278ea52e88c1699b2f2256 (diff)
downloaddjango-rest-framework-370274f5640d55ef71422f7a2440710a43ff900e.tar.bz2
Allow views to return HttpResponses. Add initial() hook method
Diffstat (limited to 'djangorestframework')
-rw-r--r--djangorestframework/mixins.py2
-rw-r--r--djangorestframework/tests/accept.py4
-rw-r--r--djangorestframework/tests/authentication.py4
-rw-r--r--djangorestframework/tests/breadcrumbs.py12
-rw-r--r--djangorestframework/tests/description.py14
-rw-r--r--djangorestframework/tests/files.py4
-rw-r--r--djangorestframework/tests/parsers.py8
-rw-r--r--djangorestframework/tests/renderers.py4
-rw-r--r--djangorestframework/tests/reverse.py4
-rw-r--r--djangorestframework/tests/throttling.py4
-rw-r--r--djangorestframework/tests/validators.py18
-rw-r--r--djangorestframework/views.py27
12 files changed, 59 insertions, 46 deletions
diff --git a/djangorestframework/mixins.py b/djangorestframework/mixins.py
index 62257592..90c75970 100644
--- a/djangorestframework/mixins.py
+++ b/djangorestframework/mixins.py
@@ -216,7 +216,7 @@ class RequestMixin(object):
class ResponseMixin(object):
"""
- Adds behavior for pluggable `Renderers` to a :class:`views.BaseView` or Django :class:`View` class.
+ Adds behavior for pluggable `Renderers` to a :class:`views.View` class.
Default behavior is to use standard HTTP Accept header content negotiation.
Also supports overriding the content type by specifying an ``_accept=`` parameter in the URL.
diff --git a/djangorestframework/tests/accept.py b/djangorestframework/tests/accept.py
index 293a7284..f26de633 100644
--- a/djangorestframework/tests/accept.py
+++ b/djangorestframework/tests/accept.py
@@ -1,6 +1,6 @@
from django.test import TestCase
from djangorestframework.compat import RequestFactory
-from djangorestframework.views import BaseView
+from djangorestframework.views import View
# See: http://www.useragentstring.com/
@@ -19,7 +19,7 @@ class UserAgentMungingTest(TestCase):
def setUp(self):
- class MockView(BaseView):
+ class MockView(View):
permissions = ()
def get(self, request):
diff --git a/djangorestframework/tests/authentication.py b/djangorestframework/tests/authentication.py
index 04ac471a..8254403c 100644
--- a/djangorestframework/tests/authentication.py
+++ b/djangorestframework/tests/authentication.py
@@ -6,13 +6,13 @@ from django.test import Client, TestCase
from django.utils import simplejson as json
from djangorestframework.compat import RequestFactory
-from djangorestframework.views import BaseView
+from djangorestframework.views import View
from djangorestframework import permissions
import base64
-class MockView(BaseView):
+class MockView(View):
permissions = ( permissions.IsAuthenticated, )
def post(self, request):
return {'a':1, 'b':2, 'c':3}
diff --git a/djangorestframework/tests/breadcrumbs.py b/djangorestframework/tests/breadcrumbs.py
index 1fd75634..158f1800 100644
--- a/djangorestframework/tests/breadcrumbs.py
+++ b/djangorestframework/tests/breadcrumbs.py
@@ -1,21 +1,21 @@
from django.conf.urls.defaults import patterns, url
from django.test import TestCase
from djangorestframework.utils.breadcrumbs import get_breadcrumbs
-from djangorestframework.views import BaseView
+from djangorestframework.views import View
-class Root(BaseView):
+class Root(View):
pass
-class ResourceRoot(BaseView):
+class ResourceRoot(View):
pass
-class ResourceInstance(BaseView):
+class ResourceInstance(View):
pass
-class NestedResourceRoot(BaseView):
+class NestedResourceRoot(View):
pass
-class NestedResourceInstance(BaseView):
+class NestedResourceInstance(View):
pass
urlpatterns = patterns('',
diff --git a/djangorestframework/tests/description.py b/djangorestframework/tests/description.py
index 6c494efa..1ce29112 100644
--- a/djangorestframework/tests/description.py
+++ b/djangorestframework/tests/description.py
@@ -1,5 +1,5 @@
from django.test import TestCase
-from djangorestframework.views import BaseView
+from djangorestframework.views import View
from djangorestframework.compat import apply_markdown
from djangorestframework.utils.description import get_name, get_description
@@ -35,7 +35,7 @@ MARKED_DOWN = """<h2>an example docstring</h2>
class TestViewNamesAndDescriptions(TestCase):
def test_resource_name_uses_classname_by_default(self):
"""Ensure Resource names are based on the classname by default."""
- class MockView(BaseView):
+ class MockView(View):
pass
self.assertEquals(get_name(MockView()), 'Mock')
@@ -43,13 +43,13 @@ class TestViewNamesAndDescriptions(TestCase):
#def test_resource_name_can_be_set_explicitly(self):
# """Ensure Resource names can be set using the 'name' class attribute."""
# example = 'Some Other Name'
- # class MockView(BaseView):
+ # class MockView(View):
# name = example
# self.assertEquals(get_name(MockView()), example)
def test_resource_description_uses_docstring_by_default(self):
"""Ensure Resource names are based on the docstring by default."""
- class MockView(BaseView):
+ class MockView(View):
"""an example docstring
====================
@@ -71,7 +71,7 @@ class TestViewNamesAndDescriptions(TestCase):
#def test_resource_description_can_be_set_explicitly(self):
# """Ensure Resource descriptions can be set using the 'description' class attribute."""
# example = 'Some other description'
- # class MockView(BaseView):
+ # class MockView(View):
# """docstring"""
# description = example
# self.assertEquals(get_description(MockView()), example)
@@ -79,13 +79,13 @@ class TestViewNamesAndDescriptions(TestCase):
#def test_resource_description_does_not_require_docstring(self):
# """Ensure that empty docstrings do not affect the Resource's description if it has been set using the 'description' class attribute."""
# example = 'Some other description'
- # class MockView(BaseView):
+ # class MockView(View):
# description = example
# self.assertEquals(get_description(MockView()), example)
def test_resource_description_can_be_empty(self):
"""Ensure that if a resource has no doctring or 'description' class attribute, then it's description is the empty string"""
- class MockView(BaseView):
+ class MockView(View):
pass
self.assertEquals(get_description(MockView()), '')
diff --git a/djangorestframework/tests/files.py b/djangorestframework/tests/files.py
index 3892422c..25aad9b4 100644
--- a/djangorestframework/tests/files.py
+++ b/djangorestframework/tests/files.py
@@ -1,7 +1,7 @@
from django.test import TestCase
from django import forms
from djangorestframework.compat import RequestFactory
-from djangorestframework.views import BaseView
+from djangorestframework.views import View
from djangorestframework.resources import FormResource
import StringIO
@@ -19,7 +19,7 @@ class UploadFilesTests(TestCase):
class MockResource(FormResource):
form = FileForm
- class MockView(BaseView):
+ class MockView(View):
permissions = ()
resource = MockResource
diff --git a/djangorestframework/tests/parsers.py b/djangorestframework/tests/parsers.py
index 764a8f5c..3ab1a61c 100644
--- a/djangorestframework/tests/parsers.py
+++ b/djangorestframework/tests/parsers.py
@@ -2,11 +2,11 @@
# ..
# >>> from djangorestframework.parsers import FormParser
# >>> from djangorestframework.compat import RequestFactory
-# >>> from djangorestframework.views import BaseView
+# >>> from djangorestframework.views import View
# >>> from StringIO import StringIO
# >>> from urllib import urlencode
# >>> req = RequestFactory().get('/')
-# >>> some_view = BaseView()
+# >>> some_view = View()
# >>> some_view.request = req # Make as if this request had been dispatched
#
# FormParser
@@ -85,7 +85,7 @@
# from django.test import TestCase
# from djangorestframework.compat import RequestFactory
# from djangorestframework.parsers import MultiPartParser
-# from djangorestframework.views import BaseView
+# from djangorestframework.views import View
# from StringIO import StringIO
#
# def encode_multipart_formdata(fields, files):
@@ -125,7 +125,7 @@
# def test_multipartparser(self):
# """Ensure that MultiPartParser can parse multipart/form-data that contains a mix of several files and parameters."""
# post_req = RequestFactory().post('/', self.body, content_type=self.content_type)
-# view = BaseView()
+# view = View()
# view.request = post_req
# (data, files) = MultiPartParser(view).parse(StringIO(self.body))
# self.assertEqual(data['key1'], 'val1')
diff --git a/djangorestframework/tests/renderers.py b/djangorestframework/tests/renderers.py
index fcc405a1..5364cd2e 100644
--- a/djangorestframework/tests/renderers.py
+++ b/djangorestframework/tests/renderers.py
@@ -1,7 +1,7 @@
from django.conf.urls.defaults import patterns, url
from django import http
from django.test import TestCase
-from djangorestframework.compat import View
+from djangorestframework.compat import View as DjangoView
from djangorestframework.renderers import BaseRenderer, JSONRenderer
from djangorestframework.mixins import ResponseMixin
from djangorestframework.response import Response
@@ -13,7 +13,7 @@ DUMMYCONTENT = 'dummycontent'
RENDERER_A_SERIALIZER = lambda x: 'Renderer A: %s' % x
RENDERER_B_SERIALIZER = lambda x: 'Renderer B: %s' % x
-class MockView(ResponseMixin, View):
+class MockView(ResponseMixin, DjangoView):
def get(self, request):
response = Response(DUMMYSTATUS, DUMMYCONTENT)
return self.render(response)
diff --git a/djangorestframework/tests/reverse.py b/djangorestframework/tests/reverse.py
index 7026d4a4..b4b0a793 100644
--- a/djangorestframework/tests/reverse.py
+++ b/djangorestframework/tests/reverse.py
@@ -3,10 +3,10 @@ from django.core.urlresolvers import reverse
from django.test import TestCase
from django.utils import simplejson as json
-from djangorestframework.views import BaseView
+from djangorestframework.views import View
-class MockView(BaseView):
+class MockView(View):
"""Mock resource which simply returns a URL, so that we can ensure that reversed URLs are fully qualified"""
permissions = ()
diff --git a/djangorestframework/tests/throttling.py b/djangorestframework/tests/throttling.py
index e7a054cd..a8f08b18 100644
--- a/djangorestframework/tests/throttling.py
+++ b/djangorestframework/tests/throttling.py
@@ -3,11 +3,11 @@ from django.test import TestCase
from django.utils import simplejson as json
from djangorestframework.compat import RequestFactory
-from djangorestframework.views import BaseView
+from djangorestframework.views import View
from djangorestframework.permissions import PerUserThrottling
-class MockView(BaseView):
+class MockView(View):
permissions = ( PerUserThrottling, )
throttle = (3, 1) # 3 requests per second
diff --git a/djangorestframework/tests/validators.py b/djangorestframework/tests/validators.py
index 32fb1002..a1e5d2d7 100644
--- a/djangorestframework/tests/validators.py
+++ b/djangorestframework/tests/validators.py
@@ -4,7 +4,7 @@ from django.test import TestCase
from djangorestframework.compat import RequestFactory
from djangorestframework.resources import Resource, FormResource, ModelResource
from djangorestframework.response import ErrorResponse
-from djangorestframework.views import BaseView
+from djangorestframework.views import View
from djangorestframework.resources import Resource
@@ -18,7 +18,7 @@ class TestDisabledValidations(TestCase):
class DisabledFormResource(FormResource):
form = None
- class MockView(BaseView):
+ class MockView(View):
resource = DisabledFormResource
view = MockView()
@@ -31,7 +31,7 @@ class TestDisabledValidations(TestCase):
class DisabledFormResource(FormResource):
form = None
- class MockView(BaseView):
+ class MockView(View):
resource = DisabledFormResource
view = MockView()
@@ -43,7 +43,7 @@ class TestDisabledValidations(TestCase):
"""If the view's form is None and does not have a Resource with a model set then
ModelFormValidator(view).validate_request(content, None) should just return the content unmodified."""
- class DisabledModelFormView(BaseView):
+ class DisabledModelFormView(View):
resource = ModelResource
view = DisabledModelFormView()
@@ -52,7 +52,7 @@ class TestDisabledValidations(TestCase):
def test_disabled_model_form_validator_get_bound_form_returns_none(self):
"""If the form attribute is None on FormValidatorMixin then get_bound_form(content) should just return None."""
- class DisabledModelFormView(BaseView):
+ class DisabledModelFormView(View):
resource = ModelResource
view = DisabledModelFormView()
@@ -77,7 +77,7 @@ class TestNonFieldErrors(TestCase):
class MockResource(FormResource):
form = MockForm
- class MockView(BaseView):
+ class MockView(View):
pass
view = MockView()
@@ -104,10 +104,10 @@ class TestFormValidation(TestCase):
class MockModelResource(ModelResource):
form = MockForm
- class MockFormView(BaseView):
+ class MockFormView(View):
resource = MockFormResource
- class MockModelFormView(BaseView):
+ class MockModelFormView(View):
resource = MockModelResource
self.MockFormResource = MockFormResource
@@ -277,7 +277,7 @@ class TestModelFormValidator(TestCase):
class MockResource(ModelResource):
model = MockModel
- class MockView(BaseView):
+ class MockView(View):
resource = MockResource
self.validator = MockResource(MockView)
diff --git a/djangorestframework/views.py b/djangorestframework/views.py
index 545671a4..3d6a6c40 100644
--- a/djangorestframework/views.py
+++ b/djangorestframework/views.py
@@ -6,16 +6,17 @@ By setting or modifying class attributes on your view, you change it's predefine
"""
from django.core.urlresolvers import set_script_prefix
+from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
-from djangorestframework.compat import View
+from djangorestframework.compat import View as DjangoView
from djangorestframework.response import Response, ErrorResponse
from djangorestframework.mixins import *
from djangorestframework import resources, renderers, parsers, authentication, permissions, status
__all__ = (
- 'BaseView',
+ 'View',
'ModelView',
'InstanceModelView',
'ListModelView',
@@ -24,7 +25,7 @@ __all__ = (
-class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
+class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
"""
Handles incoming requests and maps them to REST operations.
Performs request deserialization, response serialization, authentication and input validation.
@@ -65,7 +66,7 @@ class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
as an attribute on the callable function. This allows us to discover
information about the view when we do URL reverse lookups.
"""
- view = super(BaseView, cls).as_view(**initkwargs)
+ view = super(View, cls).as_view(**initkwargs)
view.cls_instance = cls(**initkwargs)
return view
@@ -86,6 +87,14 @@ class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
{'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
+
# Note: session based authentication is explicitly CSRF validated,
# all other authentication is CSRF exempt.
@csrf_exempt
@@ -99,6 +108,8 @@ class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
set_script_prefix(prefix)
try:
+ self.initial(request, *args, **kwargs)
+
# Authenticate and check request has the relevant permissions
self._check_permissions()
@@ -110,8 +121,10 @@ class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
response_obj = handler(request, *args, **kwargs)
- # Allow return value to be either Response, or an object, or None
- if isinstance(response_obj, Response):
+ # 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)
@@ -135,7 +148,7 @@ class BaseView(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, View):
-class ModelView(BaseView):
+class ModelView(View):
"""A RESTful view that maps to a model in the database."""
resource = resources.ModelResource