From 09b75f2d6fb860ca3658a6acf3623c5f4dd7ae85 Mon Sep 17 00:00:00 2001 From: shipengtao Date: Wed, 27 Jul 2022 17:38:01 +0800 Subject: [PATCH] fix multiple actions having the same url_path --- src/drf_yasg/generators.py | 13 +++++++------ tests/test_schema_generator.py | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/drf_yasg/generators.py b/src/drf_yasg/generators.py index 36a1f07f..bf48e436 100644 --- a/src/drf_yasg/generators.py +++ b/src/drf_yasg/generators.py @@ -94,13 +94,14 @@ def get_api_endpoints(self, patterns=None, prefix='', app_name=None, namespace=N if self.should_include_endpoint(path, callback, app_name or '', namespace or '', url_name): path = self.replace_version(path, callback) - # avoid adding endpoints that have already been seen, - # as Django resolves urls in top-down order - if path in ignored_endpoints: - continue - ignored_endpoints.add(path) - for method in self.get_allowed_methods(callback): + # avoid adding endpoints that have already been seen, + # as Django resolves urls in top-down order + ignore_endpoint = (path, method) + if ignore_endpoint in ignored_endpoints: + continue + ignored_endpoints.add(ignore_endpoint) + endpoint = (path, method, callback) api_endpoints.append(endpoint) except Exception: # pragma: no cover diff --git a/tests/test_schema_generator.py b/tests/test_schema_generator.py index 9be43456..46817e88 100644 --- a/tests/test_schema_generator.py +++ b/tests/test_schema_generator.py @@ -206,6 +206,41 @@ def action_post(self, request): assert action_ops['delete']['description'] == 'mapping docstring get/delete' +@pytest.mark.skipif(not MethodMapper or not action, reason="actions - same url_path ") +def test_action_same_url_path(): + class ActionViewSet(viewsets.ViewSet): + @swagger_auto_schema(method='get', operation_id='method_get') + @action(detail=False, methods=['get'], url_path='test') + def action_get(self, request): + """docstring get""" + pass + + @swagger_auto_schema(method='post', operation_id='method_post') + @action(detail=False, methods=['post'], url_path='test') + def action_post(self, request): + """docstring post""" + pass + + router = routers.DefaultRouter() + router.register(r'action', ActionViewSet, **_basename_or_base_name('action')) + + generator = OpenAPISchemaGenerator( + info=openapi.Info(title="Test generator", default_version="v1"), + version="v2", + url='', + patterns=router.urls + ) + + for _ in range(3): + swagger = generator.get_schema(None, True) + action_ops = swagger['paths']['/test/'] + methods = ['get', 'post'] + assert all(mth in action_ops for mth in methods) + assert all(action_ops[mth]['operationId'] == 'method_' + mth for mth in methods) + assert action_ops['post']['description'] == 'docstring post' + assert action_ops['get']['description'] == 'docstring get' + + @pytest.mark.parametrize('choices, expected_type', [ (['A', 'B'], openapi.TYPE_STRING), ([u'A', u'B'], openapi.TYPE_STRING),