Merge list/detail route decorators into 'action'

This commit is contained in:
Ryan P Kilby 2017-12-22 01:18:00 -05:00
parent 5fc35eb7eb
commit f79cd591fa
2 changed files with 71 additions and 18 deletions

View File

@ -130,29 +130,43 @@ def schema(view_inspector):
return decorator
def action(methods=None, detail=True, **kwargs):
"""
Mark a ViewSet method as a routable action.
Set the `detail` boolean to determine if this action should apply to
instance/detail requests or collection/list requests.
"""
methods = ['get'] if (methods is None) else methods
methods = [method.lower() for method in methods]
def decorator(func):
func.bind_to_methods = methods
func.detail = detail
func.kwargs = kwargs
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.
"""
methods = ['get'] if (methods is None) else methods
def decorator(func):
func.bind_to_methods = methods
func.detail = True
func.kwargs = kwargs
return func
return decorator
warnings.warn(
"`detail_route` is pending deprecation and will be removed in 3.10 in favor of "
"`action`, which accepts a `detail` bool. Use `@action(detail=True)` instead.",
PendingDeprecationWarning, stacklevel=2
)
return action(methods, detail=True, **kwargs)
def list_route(methods=None, **kwargs):
"""
Used to mark a method on a ViewSet that should be routed for list requests.
"""
methods = ['get'] if (methods is None) else methods
def decorator(func):
func.bind_to_methods = methods
func.detail = False
func.kwargs = kwargs
return func
return decorator
warnings.warn(
"`list_route` is pending deprecation and will be removed in 3.10 in favor of "
"`action`, which accepts a `detail` bool. Use `@action(detail=False)` instead.",
PendingDeprecationWarning, stacklevel=2
)
return action(methods, detail=False, **kwargs)

View File

@ -1,12 +1,14 @@
from __future__ import unicode_literals
import pytest
from django.test import TestCase
from rest_framework import status
from rest_framework.authentication import BasicAuthentication
from rest_framework.decorators import (
api_view, authentication_classes, parser_classes, permission_classes,
renderer_classes, schema, throttle_classes
action, api_view, authentication_classes, detail_route, list_route,
parser_classes, permission_classes, renderer_classes, schema,
throttle_classes
)
from rest_framework.parsers import JSONParser
from rest_framework.permissions import IsAuthenticated
@ -166,3 +168,40 @@ class DecoratorTestCase(TestCase):
return Response({})
assert isinstance(view.cls.schema, CustomSchema)
class ActionDecoratorTestCase(TestCase):
def test_defaults(self):
@action()
def test_action(request):
pass
assert test_action.bind_to_methods == ['get']
assert test_action.detail is True
def test_detail_route_deprecation(self):
with pytest.warns(PendingDeprecationWarning) as record:
@detail_route()
def view(request):
pass
assert len(record) == 1
assert str(record[0].message) == (
"`detail_route` is pending deprecation and will be removed in "
"3.10 in favor of `action`, which accepts a `detail` bool. Use "
"`@action(detail=True)` instead."
)
def test_list_route_deprecation(self):
with pytest.warns(PendingDeprecationWarning) as record:
@list_route()
def view(request):
pass
assert len(record) == 1
assert str(record[0].message) == (
"`list_route` is pending deprecation and will be removed in "
"3.10 in favor of `action`, which accepts a `detail` bool. Use "
"`@action(detail=False)` instead."
)