mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-06-18 20:43:29 +03:00
Update to new rest_framework package name, simplify implementation
This commit is contained in:
parent
4be937a9b3
commit
c13c8fe5bc
|
@ -6,95 +6,78 @@ from rest_framework import status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framwork.views import APIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
|
|
||||||
class LazyViewCreator(object):
|
def api_view(http_method_names):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This class is responsible for dynamically creating an APIView subclass that
|
Decorator that converts a function-based view into an APIView subclass.
|
||||||
will wrap a function-based view. Instances of this class are created
|
Takes a list of allowed methods for the view as an argument.
|
||||||
by the function-based view decorators (below), and each decorator is
|
|
||||||
responsible for setting attributes on the instance that will eventually be
|
|
||||||
copied onto the final class-based view. The CBV gets created lazily the first
|
|
||||||
time it's needed, and then cached for future use.
|
|
||||||
|
|
||||||
This is done so that the ordering of stacked decorators is irrelevant.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, wrapped_view):
|
def decorator(func):
|
||||||
|
|
||||||
self.wrapped_view = wrapped_view
|
|
||||||
|
|
||||||
# Each item in this dictionary will be copied onto the final
|
|
||||||
# class-based view that gets created when this object is called
|
|
||||||
self.final_view_attrs = {
|
|
||||||
'http_method_names': APIView.http_method_names,
|
|
||||||
'renderer_classes': APIView.renderer_classes,
|
|
||||||
'parser_classes': APIView.parser_classes,
|
|
||||||
'authentication_classes': APIView.authentication_classes,
|
|
||||||
'throttle_classes': APIView.throttle_classes,
|
|
||||||
'permission_classes': APIView.permission_classes,
|
|
||||||
}
|
|
||||||
self._cached_view = None
|
|
||||||
|
|
||||||
def handler(self, *args, **kwargs):
|
|
||||||
return self.wrapped_view(*args, **kwargs)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def view(self):
|
|
||||||
"""
|
|
||||||
Accessor for the dynamically created class-based view. This will
|
|
||||||
be created if necessary and cached for next time.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if self._cached_view is None:
|
|
||||||
|
|
||||||
class WrappedAPIView(APIView):
|
class WrappedAPIView(APIView):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for attr, value in self.final_view_attrs.items():
|
WrappedAPIView.http_method_names = [method.lower() for method in http_method_names]
|
||||||
setattr(WrappedAPIView, attr, value)
|
|
||||||
|
|
||||||
# Attach the wrapped view function for each of the
|
def handler(self, *args, **kwargs):
|
||||||
# allowed HTTP methods
|
return func(*args, **kwargs)
|
||||||
for method in WrappedAPIView.http_method_names:
|
|
||||||
setattr(WrappedAPIView, method.lower(), self.handler)
|
|
||||||
|
|
||||||
self._cached_view = WrappedAPIView.as_view()
|
for method in http_method_names:
|
||||||
|
setattr(WrappedAPIView, method.lower(), handler)
|
||||||
|
|
||||||
return self._cached_view
|
WrappedAPIView.renderer_classes = getattr(func, 'renderer_classes',
|
||||||
|
APIView.renderer_classes)
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
WrappedAPIView.parser_classes = getattr(func, 'parser_classes',
|
||||||
"""
|
APIView.parser_classes)
|
||||||
This is the actual code that gets run per-request
|
|
||||||
"""
|
|
||||||
return self.view(*args, **kwargs)
|
|
||||||
|
|
||||||
@staticmethod
|
WrappedAPIView.authentication_classes = getattr(func, 'authentication_classes',
|
||||||
def maybe_create(func_or_instance):
|
APIView.authentication_classes)
|
||||||
"""
|
|
||||||
If the argument is already an instance of LazyViewCreator,
|
|
||||||
just return it. Otherwise, create a new one.
|
|
||||||
"""
|
|
||||||
if isinstance(func_or_instance, LazyViewCreator):
|
|
||||||
return func_or_instance
|
|
||||||
return LazyViewCreator(func_or_instance)
|
|
||||||
|
|
||||||
|
WrappedAPIView.throttle_classes = getattr(func, 'throttle_classes',
|
||||||
|
APIView.throttle_classes)
|
||||||
|
|
||||||
def _create_attribute_setting_decorator(attribute, filter=lambda item: item):
|
WrappedAPIView.permission_classes = getattr(func, 'permission_classes',
|
||||||
def decorator(value):
|
APIView.permission_classes)
|
||||||
def inner(func):
|
|
||||||
wrapper = LazyViewCreator.maybe_create(func)
|
return WrappedAPIView.as_view()
|
||||||
wrapper.final_view_attrs[attribute] = filter(value)
|
|
||||||
return wrapper
|
|
||||||
return inner
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
api_view = _create_attribute_setting_decorator('http_method_names', filter=lambda methods: [method.lower() for method in methods])
|
def renderer_classes(renderer_classes):
|
||||||
renderer_classes = _create_attribute_setting_decorator('renderer_classes')
|
def decorator(func):
|
||||||
parser_classes = _create_attribute_setting_decorator('parser_classes')
|
setattr(func, 'renderer_classes', renderer_classes)
|
||||||
authentication_classes = _create_attribute_setting_decorator('authentication_classes')
|
return func
|
||||||
throttle_classes = _create_attribute_setting_decorator('throttle_classes')
|
return decorator
|
||||||
permission_classes = _create_attribute_setting_decorator('permission_classes')
|
|
||||||
|
|
||||||
|
def parser_classes(parser_classes):
|
||||||
|
def decorator(func):
|
||||||
|
setattr(func, 'parser_classes', parser_classes)
|
||||||
|
return func
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def authentication_classes(authentication_classes):
|
||||||
|
def decorator(func):
|
||||||
|
setattr(func, 'authentication_classes', authentication_classes)
|
||||||
|
return func
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def throttle_classes(throttle_classes):
|
||||||
|
def decorator(func):
|
||||||
|
setattr(func, 'throttle_classes', throttle_classes)
|
||||||
|
return func
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def permission_classes(permission_classes):
|
||||||
|
def decorator(func):
|
||||||
|
setattr(func, 'permission_classes', permission_classes)
|
||||||
|
return func
|
||||||
|
return decorator
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from djangorestframework.response import Response
|
from rest_framework.response import Response
|
||||||
from djangorestframework.compat import RequestFactory
|
from rest_framework.compat import RequestFactory
|
||||||
from djangorestframework.renderers import JSONRenderer
|
from rest_framework.renderers import JSONRenderer
|
||||||
from djangorestframework.parsers import JSONParser
|
from rest_framework.parsers import JSONParser
|
||||||
from djangorestframework.authentication import BasicAuthentication
|
from rest_framework.authentication import BasicAuthentication
|
||||||
from djangorestframework.throttling import SimpleRateThottle
|
from rest_framework.throttling import SimpleRateThottle
|
||||||
from djangorestframework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from djangorestframework.decorators import (
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework.decorators import (
|
||||||
api_view,
|
api_view,
|
||||||
renderer_classes,
|
renderer_classes,
|
||||||
parser_classes,
|
parser_classes,
|
||||||
authentication_classes,
|
authentication_classes,
|
||||||
throttle_classes,
|
throttle_classes,
|
||||||
permission_classes,
|
permission_classes,
|
||||||
LazyViewCreator
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,13 +22,18 @@ class DecoratorTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.factory = RequestFactory()
|
self.factory = RequestFactory()
|
||||||
|
|
||||||
|
def _finalize_response(self, request, response, *args, **kwargs):
|
||||||
|
print "HAI"
|
||||||
|
response.request = request
|
||||||
|
return APIView.finalize_response(self, request, response, *args, **kwargs)
|
||||||
|
|
||||||
def test_wrap_view(self):
|
def test_wrap_view(self):
|
||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
def view(request):
|
def view(request):
|
||||||
return Response({})
|
return Response({})
|
||||||
|
|
||||||
self.assertTrue(isinstance(view, LazyViewCreator))
|
self.assertTrue(isinstance(view.cls_instance, APIView))
|
||||||
|
|
||||||
def test_calling_method(self):
|
def test_calling_method(self):
|
||||||
|
|
||||||
|
@ -46,57 +51,57 @@ class DecoratorTestCase(TestCase):
|
||||||
|
|
||||||
def test_renderer_classes(self):
|
def test_renderer_classes(self):
|
||||||
|
|
||||||
@renderer_classes([JSONRenderer])
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
|
@renderer_classes([JSONRenderer])
|
||||||
def view(request):
|
def view(request):
|
||||||
return Response({})
|
return Response({})
|
||||||
|
|
||||||
request = self.factory.get('/')
|
request = self.factory.get('/')
|
||||||
response = view(request)
|
response = view(request)
|
||||||
self.assertEqual(response.renderer_classes, [JSONRenderer])
|
self.assertTrue(isinstance(response.renderer, JSONRenderer))
|
||||||
|
|
||||||
def test_parser_classes(self):
|
def test_parser_classes(self):
|
||||||
|
|
||||||
@parser_classes([JSONParser])
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
|
@parser_classes([JSONParser])
|
||||||
def view(request):
|
def view(request):
|
||||||
|
self.assertEqual(request.parser_classes, [JSONParser])
|
||||||
return Response({})
|
return Response({})
|
||||||
|
|
||||||
request = self.factory.get('/')
|
request = self.factory.get('/')
|
||||||
response = view(request)
|
view(request)
|
||||||
self.assertEqual(response.request.parser_classes, [JSONParser])
|
|
||||||
|
|
||||||
def test_authentication_classes(self):
|
def test_authentication_classes(self):
|
||||||
|
|
||||||
@authentication_classes([BasicAuthentication])
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
|
@authentication_classes([BasicAuthentication])
|
||||||
def view(request):
|
def view(request):
|
||||||
|
self.assertEqual(request.authentication_classes, [BasicAuthentication])
|
||||||
return Response({})
|
return Response({})
|
||||||
|
|
||||||
request = self.factory.get('/')
|
request = self.factory.get('/')
|
||||||
response = view(request)
|
view(request)
|
||||||
self.assertEqual(response.request.authentication_classes, [BasicAuthentication])
|
|
||||||
|
|
||||||
# Doesn't look like these bits are working quite yet
|
def test_permission_classes(self):
|
||||||
|
|
||||||
|
@api_view(['GET'])
|
||||||
|
@permission_classes([IsAuthenticated])
|
||||||
|
def view(request):
|
||||||
|
self.assertEqual(request.permission_classes, [IsAuthenticated])
|
||||||
|
return Response({})
|
||||||
|
|
||||||
|
request = self.factory.get('/')
|
||||||
|
view(request)
|
||||||
|
|
||||||
|
# Doesn't look like this bits are working quite yet
|
||||||
|
|
||||||
# def test_throttle_classes(self):
|
# def test_throttle_classes(self):
|
||||||
#
|
|
||||||
|
# @api_view(['GET'])
|
||||||
# @throttle_classes([SimpleRateThottle])
|
# @throttle_classes([SimpleRateThottle])
|
||||||
# @api_view(['GET'])
|
|
||||||
# def view(request):
|
|
||||||
# return Response({})
|
|
||||||
#
|
|
||||||
# request = self.factory.get('/')
|
|
||||||
# response = view(request)
|
|
||||||
# self.assertEqual(response.request.throttle, [SimpleRateThottle])
|
|
||||||
|
|
||||||
# def test_permission_classes(self):
|
|
||||||
|
|
||||||
# @permission_classes([IsAuthenticated])
|
|
||||||
# @api_view(['GET'])
|
|
||||||
# def view(request):
|
# def view(request):
|
||||||
|
# self.assertEqual(request.throttle_classes, [SimpleRateThottle])
|
||||||
# return Response({})
|
# return Response({})
|
||||||
|
|
||||||
# request = self.factory.get('/')
|
# request = self.factory.get('/')
|
||||||
# response = view(request)
|
# view(request)
|
||||||
# self.assertEqual(response.request.permission_classes, [IsAuthenticated])
|
|
Loading…
Reference in New Issue
Block a user