Add extra_attrs decorator for function-based view.

In this way, function-based view will have same behavior with
class view.
This commit is contained in:
Andy Fang 2019-11-23 10:29:35 +08:00
parent a73d3c309f
commit f2c8773e05
3 changed files with 49 additions and 1 deletions

View File

@ -217,6 +217,21 @@ You may pass `None` in order to exclude the view from schema generation.
return Response({"message": "Will not appear in schema!"})
## View extra attrs decorator
To set custom extra attribute on function-based view, you may use the `@extra_attrs` decorator.
This must come *after* (below) the `@api_view` decorator. For example:
from rest_framework.decorators import api_view, extra_attrs
class ExtraClass:
pass
@api_view(['GET'])
@extra_attrs(extra_class=ExtraClass)
def view(request):
return Response({"message": "Hello for today! See you tomorrow!"})
[cite]: https://reinout.vanrees.org/weblog/2011/08/24/class-based-views-usage.html
[cite2]: http://www.boredomandlaziness.org/2012/05/djangos-cbvs-are-not-mistake-but.html
[settings]: settings.md

View File

@ -72,6 +72,11 @@ def api_view(http_method_names=None):
WrappedAPIView.schema = getattr(func, 'schema',
APIView.schema)
for extra_attr in getattr(func, 'extra_attrs', []):
assert not (hasattr(WrappedAPIView, extra_attr)), \
'{} already has attribute {}'.format(func.__name__, extra_attr)
setattr(WrappedAPIView, extra_attr,
getattr(func, extra_attr, None))
return WrappedAPIView.as_view()
@ -120,6 +125,15 @@ def schema(view_inspector):
return decorator
def extra_attrs(**kwargs):
def decorator(func):
func.extra_attrs = list(kwargs.keys())
for extra_attr, val in kwargs.items():
setattr(func, extra_attr, val)
return func
return decorator
def action(methods=None, detail=None, url_path=None, url_name=None, **kwargs):
"""
Mark a ViewSet method as a routable action.

View File

@ -4,7 +4,7 @@ from django.test import TestCase
from rest_framework import status
from rest_framework.authentication import BasicAuthentication
from rest_framework.decorators import (
action, api_view, authentication_classes, parser_classes,
action, api_view, authentication_classes, extra_attrs, parser_classes,
permission_classes, renderer_classes, schema, throttle_classes
)
from rest_framework.parsers import JSONParser
@ -166,6 +166,25 @@ class DecoratorTestCase(TestCase):
assert isinstance(view.cls.schema, CustomSchema)
def test_extra_attrs(self):
"""
Checks Custom extra attrs is set on view
"""
def extra_func():
pass
class ExtraClass:
pass
@api_view(['get'])
@extra_attrs(extra_func=extra_func, extra_class=ExtraClass)
def view(request):
return Response({})
assert view.cls.extra_func is extra_func
assert view.cls.extra_class is ExtraClass
class ActionDecoratorTestCase(TestCase):