diff --git a/rest_framework/decorators.py b/rest_framework/decorators.py index 3020edc16..62afa0597 100644 --- a/rest_framework/decorators.py +++ b/rest_framework/decorators.py @@ -130,7 +130,7 @@ def schema(view_inspector): return decorator -def action(methods=None, detail=True, url_path=None, url_name=None, **kwargs): +def action(methods=None, detail=None, url_path=None, url_name=None, **kwargs): """ Mark a ViewSet method as a routable action. @@ -140,6 +140,10 @@ def action(methods=None, detail=True, url_path=None, url_name=None, **kwargs): methods = ['get'] if (methods is None) else methods methods = [method.lower() for method in methods] + assert detail is not None, ( + "@action() missing required argument: 'detail'" + ) + def decorator(func): func.bind_to_methods = methods func.detail = detail diff --git a/tests/test_decorators.py b/tests/test_decorators.py index a86cb5a3e..674990730 100644 --- a/tests/test_decorators.py +++ b/tests/test_decorators.py @@ -173,7 +173,7 @@ class DecoratorTestCase(TestCase): class ActionDecoratorTestCase(TestCase): def test_defaults(self): - @action() + @action(detail=True) def test_action(request): pass @@ -182,6 +182,14 @@ class ActionDecoratorTestCase(TestCase): assert test_action.url_path == 'test_action' assert test_action.url_name == 'test-action' + def test_detail_required(self): + with pytest.raises(AssertionError) as excinfo: + @action() + def test_action(request): + pass + + assert str(excinfo.value) == "@action() missing required argument: 'detail'" + def test_detail_route_deprecation(self): with pytest.warns(PendingDeprecationWarning) as record: @detail_route()