From 8dfa39085c5d57de9c540ac772f5cb4afc026bfd Mon Sep 17 00:00:00 2001 From: bergran Date: Tue, 4 Feb 2020 00:37:47 +0100 Subject: [PATCH] Added openapi_tags for group by tags as openapi specification --- rest_framework/schemas/openapi.py | 19 ++++++++++++++ tests/schemas/test_openapi.py | 42 +++++++++++++++++++++++++++++++ tests/schemas/views.py | 11 ++++++++ 3 files changed, 72 insertions(+) diff --git a/rest_framework/schemas/openapi.py b/rest_framework/schemas/openapi.py index 9c6610eaf..03a6f748b 100644 --- a/rest_framework/schemas/openapi.py +++ b/rest_framework/schemas/openapi.py @@ -87,6 +87,7 @@ class AutoSchema(ViewInspector): operation['operationId'] = self._get_operation_id(path, method) operation['description'] = self.get_description(path, method) + operation['tags'] = self._get_tags(path, method) parameters = [] parameters += self._get_path_parameters(path, method) @@ -211,6 +212,24 @@ class AutoSchema(ViewInspector): return paginator.get_schema_operation_parameters(view) + def _get_tags(self, path, method): + """ + Get tags parameters from view + + Default value to return it will be tuple with default tag + In other hand it will try to get it from openapi_tags of view + """ + + tags = ['default'] + + if hasattr(self.view, 'openapi_tags'): + tags = getattr(self.view, 'openapi_tags', tags) + + assert type(tags) == list, 'openapi_tags property is not a list' + assert len(tags) > 0, 'openapi_tags property should has almost one tag' + + return tags + def _map_choicefield(self, field): choices = list(OrderedDict.fromkeys(field.choices)) # preserve order and remove duplicates if all(isinstance(choice, bool) for choice in choices): diff --git a/tests/schemas/test_openapi.py b/tests/schemas/test_openapi.py index cfa2e89ef..da01bd925 100644 --- a/tests/schemas/test_openapi.py +++ b/tests/schemas/test_openapi.py @@ -125,6 +125,7 @@ class TestOperationIntrospection(TestCase): assert operation == { 'operationId': 'listDocStringExamples', 'description': 'A description of my GET operation.', + 'tags': ['default'], 'parameters': [], 'responses': { '200': { @@ -157,6 +158,47 @@ class TestOperationIntrospection(TestCase): assert operation == { 'operationId': 'RetrieveDocStringExampleDetail', 'description': 'A description of my GET operation.', + 'tags': ['default'], + 'parameters': [{ + 'description': '', + 'in': 'path', + 'name': 'id', + 'required': True, + 'schema': { + 'type': 'string', + }, + }], + 'responses': { + '200': { + 'description': '', + 'content': { + 'application/json': { + 'schema': { + }, + }, + }, + }, + }, + } + + def test_modify_openapi_tags(self): + path = '/example/{id}/' + method = 'GET' + + view = create_view( + views.DocStringExampleDetailWithTagsView, + method, + create_request(path) + ) + inspector = AutoSchema() + inspector.view = view + + operation = inspector.get_operation(path, method) + + assert operation == { + 'operationId': 'RetrieveDocStringExampleDetailWithTags', + 'description': 'A description of my GET operation.', + 'tags': ['DocString'], 'parameters': [{ 'description': '', 'in': 'path', diff --git a/tests/schemas/views.py b/tests/schemas/views.py index e8307ccbd..ec08eecc6 100644 --- a/tests/schemas/views.py +++ b/tests/schemas/views.py @@ -53,6 +53,17 @@ class DocStringExampleDetailView(APIView): pass +class DocStringExampleDetailWithTagsView(APIView): + permission_classes = [permissions.IsAuthenticatedOrReadOnly] + openapi_tags = ['DocString'] + + def get(self, *args, **kwargs): + """ + A description of my GET operation. + """ + pass + + # Generics. class ExampleSerializer(serializers.Serializer): date = serializers.DateField()