Allow views to return HttpResponses. Add initial() hook method

This commit is contained in:
Tom Christie 2011-05-24 10:27:24 +01:00
parent 698df527a3
commit 370274f564
16 changed files with 70 additions and 57 deletions

View File

@ -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.

View File

@ -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):

View File

@ -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}

View File

@ -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('',

View File

@ -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()), '')

View File

@ -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

View File

@ -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')

View File

@ -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)

View File

@ -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 = ()

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -1,7 +1,7 @@
from django.conf import settings
from django.core.urlresolvers import reverse
from djangorestframework.views import BaseView
from djangorestframework.views import View
from djangorestframework.response import Response
from djangorestframework import status
@ -25,7 +25,7 @@ def remove_oldest_files(dir, max_files):
[os.remove(path) for path in ctime_sorted_paths[max_files:]]
class ObjectStoreRoot(BaseView):
class ObjectStoreRoot(View):
"""
Root of the Object Store API.
Allows the client to get a complete list of all the stored objects, or to create a new stored object.
@ -51,7 +51,7 @@ class ObjectStoreRoot(BaseView):
return Response(status.HTTP_201_CREATED, self.CONTENT, {'Location': reverse('stored-object', kwargs={'key':key})})
class StoredObject(BaseView):
class StoredObject(View):
"""
Represents a stored object.
The object may be any picklable content.

View File

@ -5,7 +5,7 @@ from django.core.urlresolvers import reverse
from djangorestframework.resources import FormResource
from djangorestframework.response import Response
from djangorestframework.renderers import BaseRenderer
from djangorestframework.views import BaseView
from djangorestframework.views import View
from djangorestframework import status
from pygments.formatters import HtmlFormatter
@ -53,7 +53,7 @@ class PygmentsFormResource(FormResource):
form = PygmentsForm
class PygmentsRoot(BaseView):
class PygmentsRoot(View):
"""
This example demonstrates a simple RESTful Web API aound the awesome pygments library.
This top level resource is used to create highlighted code snippets, and to list all the existing code snippets.
@ -88,7 +88,7 @@ class PygmentsRoot(BaseView):
return Response(status.HTTP_201_CREATED, headers={'Location': reverse('pygments-instance', args=[unique_id])})
class PygmentsInstance(BaseView):
class PygmentsInstance(View):
"""
Simply return the stored highlighted HTML file with the correct mime type.
This Resource only renders HTML and uses a standard HTML renderer rather than the renderers.DocumentingHTMLRenderer class.

View File

@ -1,6 +1,6 @@
from django.core.urlresolvers import reverse
from djangorestframework.views import BaseView
from djangorestframework.views import View
from djangorestframework.resources import FormResource
from djangorestframework.response import Response
from djangorestframework import status
@ -14,7 +14,7 @@ class MyFormValidation(FormResource):
form = MyForm
class ExampleResource(BaseView):
class ExampleResource(View):
"""
A basic read-only resource that points to 3 other resources.
"""
@ -23,7 +23,7 @@ class ExampleResource(BaseView):
return {"Some other resources": [reverse('another-example-resource', kwargs={'num':num}) for num in range(3)]}
class AnotherExampleResource(BaseView):
class AnotherExampleResource(View):
"""
A basic GET-able/POST-able resource.
"""

View File

@ -1,10 +1,10 @@
"""The root view for the examples provided with Django REST framework"""
from django.core.urlresolvers import reverse
from djangorestframework.views import BaseView
from djangorestframework.views import View
class Sandbox(BaseView):
class Sandbox(View):
"""This is the sandbox for the examples provided with [Django REST framework](http://django-rest-framework.org).
These examples are provided to help you get a better idea of the some of the features of RESTful APIs created using the framework.