django-rest-framework/rest_framework/decorators.py

139 lines
4.3 KiB
Python
Raw Normal View History

2013-04-25 15:47:34 +04:00
"""
2013-05-28 18:09:23 +04:00
The most important decorator in this module is `@api_view`, which is used
2013-04-25 15:47:34 +04:00
for writing function-based views with REST framework.
There are also various decorators for setting the API policies on function
based views, as well as the `@detail_route` and `@list_route` decorators, which are
2013-04-25 15:47:34 +04:00
used to annotate methods on viewsets that should be included by routers.
"""
from __future__ import unicode_literals
import types
from django.utils import six
from rest_framework.views import APIView
2012-09-14 19:07:07 +04:00
2014-11-28 18:55:02 +03:00
def api_view(http_method_names=None):
2012-09-14 19:07:07 +04:00
"""
Decorator that converts a function-based view into an APIView subclass.
Takes a list of allowed methods for the view as an argument.
2012-09-14 19:07:07 +04:00
"""
2015-02-04 17:26:23 +03:00
http_method_names = ['GET'] if (http_method_names is None) else http_method_names
2012-09-14 19:07:07 +04:00
def decorator(func):
2012-10-29 18:41:33 +04:00
WrappedAPIView = type(
six.PY3 and 'WrappedAPIView' or b'WrappedAPIView',
2012-10-29 18:41:33 +04:00
(APIView,),
{'__doc__': func.__doc__}
)
# Note, the above allows us to set the docstring.
2012-11-14 22:36:29 +04:00
# It is the equivalent of:
2012-10-29 18:41:33 +04:00
#
# class WrappedAPIView(APIView):
# pass
# WrappedAPIView.__doc__ = func.doc <--- Not possible to do this
# api_view applied without (method_names)
assert not(isinstance(http_method_names, types.FunctionType)), \
'@api_view missing list of allowed HTTP methods'
# api_view applied with eg. string instead of list of strings
assert isinstance(http_method_names, (list, tuple)), \
2013-05-28 18:09:23 +04:00
'@api_view expected a list of strings, received %s' % type(http_method_names).__name__
2012-10-09 15:01:17 +04:00
allowed_methods = set(http_method_names) | set(('options',))
WrappedAPIView.http_method_names = [method.lower() for method in allowed_methods]
def handler(self, *args, **kwargs):
return func(*args, **kwargs)
for method in http_method_names:
setattr(WrappedAPIView, method.lower(), handler)
WrappedAPIView.__name__ = func.__name__
WrappedAPIView.renderer_classes = getattr(func, 'renderer_classes',
APIView.renderer_classes)
WrappedAPIView.parser_classes = getattr(func, 'parser_classes',
APIView.parser_classes)
WrappedAPIView.authentication_classes = getattr(func, 'authentication_classes',
APIView.authentication_classes)
WrappedAPIView.throttle_classes = getattr(func, 'throttle_classes',
APIView.throttle_classes)
WrappedAPIView.permission_classes = getattr(func, 'permission_classes',
APIView.permission_classes)
return WrappedAPIView.as_view()
2012-09-03 18:57:43 +04:00
return decorator
2012-09-14 19:07:07 +04:00
def renderer_classes(renderer_classes):
def decorator(func):
2012-09-26 23:18:57 +04:00
func.renderer_classes = renderer_classes
return func
return decorator
def parser_classes(parser_classes):
def decorator(func):
2012-09-26 23:18:57 +04:00
func.parser_classes = parser_classes
return func
return decorator
def authentication_classes(authentication_classes):
def decorator(func):
2012-09-26 23:18:57 +04:00
func.authentication_classes = authentication_classes
return func
return decorator
def throttle_classes(throttle_classes):
def decorator(func):
2012-09-26 23:18:57 +04:00
func.throttle_classes = throttle_classes
return func
return decorator
def permission_classes(permission_classes):
def decorator(func):
2012-09-26 23:18:57 +04:00
func.permission_classes = permission_classes
return func
return decorator
def detail_route(methods=None, **kwargs):
"""
Used to mark a method on a ViewSet that should be routed for detail requests.
"""
2015-02-04 17:26:23 +03:00
methods = ['get'] if (methods is None) else methods
2015-02-04 17:13:30 +03:00
def decorator(func):
func.bind_to_methods = methods
func.detail = True
func.kwargs = kwargs
return func
return decorator
def list_route(methods=None, **kwargs):
"""
Used to mark a method on a ViewSet that should be routed for list requests.
"""
2015-02-04 17:26:23 +03:00
methods = ['get'] if (methods is None) else methods
2015-02-04 17:13:30 +03:00
def decorator(func):
func.bind_to_methods = methods
func.detail = False
func.kwargs = kwargs
return func
return decorator