allow custom name for operation_id

This commit is contained in:
Martin Desrumaux 2020-02-28 18:04:45 +01:00
parent 2a5c2f3f70
commit 2357148b12
3 changed files with 45 additions and 2 deletions

View File

@ -288,8 +288,25 @@ class MyView(APIView):
...
```
### OperationId
The schema generator generates an [operationid](openapi-operationid) for each operation. This `operationId` is deduced from the model name, serializer name or view name. The operationId may looks like "ListItems", "RetrieveItem", "UpdateItem", etc..
If you have several views with the same model, the generator may generate duplicate operationId.
In order to work around this, you can override the second part of the operationId: operation name.
```python
from rest_framework.schemas.openapi import AutoSchema
class ExampleView(APIView):
"""APIView subclass with custom schema introspection."""
schema = AutoSchema(operation_name="Custom")
```
The previous example will generate the following operationid: "ListCustoms", "RetrieveCustom", "UpdateCustom", "PartialUpdateCustom", `DestroyCustom`.
[openapi]: https://github.com/OAI/OpenAPI-Specification
[openapi-specification-extensions]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#specification-extensions
[openapi-operation]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#operationObject
[openapi-tags]: https://swagger.io/specification/#tagObject
[openapi-operationid]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#fixed-fields-17

View File

@ -88,6 +88,13 @@ class AutoSchema(ViewInspector):
'delete': 'Destroy',
}
def __init__(self, operation_name=None):
"""
:param operation_name: user-defined name in operationId. If empty, it will be deducted from the Model/Serializer/View name.
"""
super().__init__()
self.operation_name = operation_name
def get_operation(self, path, method):
operation = {}
@ -120,9 +127,13 @@ class AutoSchema(ViewInspector):
else:
action = self.method_mapping[method.lower()]
# Try to deduce the ID from the view's model
model = getattr(getattr(self.view, 'queryset', None), 'model', None)
if model is not None:
if self.operation_name is not None:
name = self.operation_name
# Try to deduce the ID from the view's model
elif model is not None:
name = model.__name__
# Try with the serializer class name

View File

@ -577,6 +577,21 @@ class TestOperationIntrospection(TestCase):
operationId = inspector._get_operation_id(path, method)
assert operationId == 'listExamples'
def test_operation_id_custom_name(self):
path = '/'
method = 'GET'
view = create_view(
views.ExampleGenericAPIView,
method,
create_request(path),
)
inspector = AutoSchema(operation_name="Ulysse")
inspector.view = view
operationId = inspector._get_operation_id(path, method)
assert operationId == 'listUlysses'
def test_repeat_operation_ids(self):
router = routers.SimpleRouter()
router.register('account', views.ExampleGenericViewSet, basename="account")