From bb020a748f3a564333cd8a6138129df1ac9a803b Mon Sep 17 00:00:00 2001 From: Carlton Gibson Date: Wed, 25 Oct 2017 10:46:52 +0200 Subject: [PATCH] Schema: Exclude OPTIONS/HEAD for ViewSet actions Closes #5528. Viewset custom actions (@detail_route etc) OPTIONS (and HEAD) methods were not being excluded from Schema Generations. This PR adds a test reproducing the reported error and adjusts `EndpointEnumerator.get_allowed_methods()` to filter ViewSet actions in the same way as other `APIView`s --- rest_framework/schemas/generators.py | 9 +++-- tests/test_schemas.py | 50 ++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/rest_framework/schemas/generators.py b/rest_framework/schemas/generators.py index 5fac352760..393e215756 100644 --- a/rest_framework/schemas/generators.py +++ b/rest_framework/schemas/generators.py @@ -222,12 +222,11 @@ def get_allowed_methods(self, callback): if hasattr(callback, 'actions'): actions = set(callback.actions.keys()) http_method_names = set(callback.cls.http_method_names) - return [method.upper() for method in actions & http_method_names] + methods = [method.upper() for method in actions & http_method_names] + else: + methods = callback.cls().allowed_methods - return [ - method for method in - callback.cls().allowed_methods if method not in ('OPTIONS', 'HEAD') - ] + return [method for method in methods if method not in ('OPTIONS', 'HEAD')] class SchemaGenerator(object): diff --git a/tests/test_schemas.py b/tests/test_schemas.py index eec3060fb4..df49103013 100644 --- a/tests/test_schemas.py +++ b/tests/test_schemas.py @@ -901,3 +901,53 @@ class TestView(generics.RetrieveAPIView): is_list = is_list_view(path, method, view) assert not is_list, "RetrieveAPIView subclasses should not be classified as list views." + + +def test_head_and_options_methods_are_excluded(): + """ + Regression test for #5528 + https://github.com/encode/django-rest-framework/issues/5528 + + Viewset OPTIONS actions were not being correctly excluded + + Initial cases here shown to be working as expected. + """ + + @api_view(['options', 'get']) + def fbv(request): + pass + + inspector = EndpointEnumerator() + + path = '/a/path/' + callback = fbv + + assert inspector.should_include_endpoint(path, callback) + assert inspector.get_allowed_methods(callback) == ["GET"] + + class AnAPIView(APIView): + + def get(self, request, *args, **kwargs): + pass + + def options(self, request, *args, **kwargs): + pass + + callback = AnAPIView.as_view() + + assert inspector.should_include_endpoint(path, callback) + assert inspector.get_allowed_methods(callback) == ["GET"] + + class AViewSet(ModelViewSet): + + @detail_route(methods=['options', 'get']) + def custom_action(self, request, pk): + pass + + callback = AViewSet.as_view({ + "options": "custom_action", + "get": "custom_action" + }) + + assert inspector.should_include_endpoint(path, callback) + assert inspector.get_allowed_methods(callback) == ["GET"] pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy