remove tag generation from viewset

This commit is contained in:
Dhaval Mehta 2020-02-20 18:14:28 +05:30
parent 48c02dd53a
commit 64a4828a06
4 changed files with 29 additions and 92 deletions

View File

@ -223,46 +223,32 @@ Tags can be used to group logical operations. Each tag name in the list MUST be
---
#### Django REST Framework generates tags automatically with the following logic:
1. Extract tag from `ViewSet`.
1. If `ViewSet` name ends with `ViewSet`, or `View`; remove it.
2. Convert class name into lowercase words & join each word using a `-`(dash).
Examples:
ViewSet Class | Tags
----------------|------------
User | ['user']
UserView | ['user']
UserViewSet | ['user']
PascalCaseXYZ | ['pascal-case-xyz']
IPAddressView | ['ip-address']
2. If View is not an instance of ViewSet, tag name will be first element from the path. Also, any `_` in path name will be replaced by a `-`.
Tag name will be first element from the path. Also, any `_` in path name will be replaced by a `-`.
Consider below examples.
Example 1: Consider a user management system. The following table will illustrate the tag generation logic.
Here first element from the paths is: `users`. Hence tag wil be `users`
Example 1: Consider a user management system. The following table will illustrate the tag generation logic.
Here first element from the paths is: `users`. Hence tag wil be `users`
Http Method | Path | Tags
-------------------------------------|-------------------|-------------
PUT, PATCH, GET(Retrieve), DELETE | /users/{id}/ | ['users']
POST, GET(List) | /users/ | ['users']
Example 2: Consider a restaurant management system. The System has restaurants. Each restaurant has branches.
Consider REST APIs to deal with a branch of a particular restaurant.
Here first element from the paths is: `restaurants`. Hence tag wil be `restaurants`.
Http Method | Path | Tags
-------------------------------------|----------------------------------------------------|-------------------
PUT, PATCH, GET(Retrieve), DELETE: | /restaurants/{restaurant_id}/branches/{branch_id} | ['restaurants']
POST, GET(List): | /restaurants/{restaurant_id}/branches/ | ['restaurants']
Example 3: Consider Order items for an e commerce company.
Http Method | Path | Tags
-------------------------------------|-------------------------|-------------
PUT, PATCH, GET(Retrieve), DELETE | /order_items/{id}/ | ['order-items']
POST, GET(List) | /order_items/ | ['order-items']
Http Method | Path | Tags
-------------------------------------|-------------------|-------------
PUT, PATCH, GET(Retrieve), DELETE | /users/{id}/ | ['users']
POST, GET(List) | /users/ | ['users']
Example 2: Consider a restaurant management system. The System has restaurants. Each restaurant has branches.
Consider REST APIs to deal with a branch of a particular restaurant.
Here first element from the paths is: `restaurants`. Hence tag wil be `restaurants`.
Http Method | Path | Tags
-------------------------------------|----------------------------------------------------|-------------------
PUT, PATCH, GET(Retrieve), DELETE: | /restaurants/{restaurant_id}/branches/{branch_id} | ['restaurants']
POST, GET(List): | /restaurants/{restaurant_id}/branches/ | ['restaurants']
Example 3: Consider Order items for an e commerce company.
Http Method | Path | Tags
-------------------------------------|-------------------------|-------------
PUT, PATCH, GET(Retrieve), DELETE | /order_items/{id}/ | ['order-items']
POST, GET(List) | /order_items/ | ['order-items']
---

View File

@ -15,7 +15,6 @@ from rest_framework import exceptions, renderers, serializers
from rest_framework.compat import uritemplate
from rest_framework.fields import _UnvalidatedField, empty
from ..utils.formatting import camelcase_to_spaces
from .generators import BaseSchemaGenerator
from .inspectors import ViewInspector
from .utils import get_pk_description, is_list_view
@ -578,18 +577,6 @@ class AutoSchema(ViewInspector):
if self._tags:
return self._tags
# Extract tag from viewset name
# UserProfileViewSet tags = [user-profile]
# UserProfileView tags = [user-profile]
# UserProfile tags = [user-profile]
if hasattr(self.view, 'action'):
name = self.view.__class__.__name__
if name.endswith('ViewSet'):
name = name[:-7]
elif name.endswith('View'):
name = name[:-4]
return [camelcase_to_spaces(name).lower().replace(' ', '-')]
# First element of a specific path could be valid tag. This is a fallback solution.
# PUT, PATCH, GET(Retrieve), DELETE: /user_profile/{id}/ tags = [user-profile]
# POST, GET(List): /user_profile/ tags = [user-profile]

View File

@ -699,14 +699,15 @@ class TestOperationIntrospection(TestCase):
assert 'format' not in properties['ip']
def test_overridden_tags(self):
class ExampleStringTagsViewSet(views.ExampleTagsViewSet):
class ExampleStringTagsViewSet(views.ExampleGenericAPIView):
schema = AutoSchema(tags=['example1', 'example2'])
router = routers.SimpleRouter()
router.register('test', ExampleStringTagsViewSet, basename="test")
generator = SchemaGenerator(patterns=router.urls)
url_patterns = [
url(r'^test/?$', ExampleStringTagsViewSet.as_view()),
]
generator = SchemaGenerator(patterns=url_patterns)
schema = generator.get_schema(request=create_request('/'))
assert schema['paths']['/test/{id}/']['get']['tags'] == ['example1', 'example2']
assert schema['paths']['/test/']['get']['tags'] == ['example1', 'example2']
def test_overridden_get_tags_method(self):
class MySchema(AutoSchema):
@ -730,32 +731,6 @@ class TestOperationIntrospection(TestCase):
assert schema['paths']['/example/new/']['get']['tags'] == ['tag1', 'tag2']
assert schema['paths']['/example/old/']['get']['tags'] == ['tag2', 'tag3']
def test_auto_generated_viewset_tags(self):
class ExampleIPViewSet(views.ExampleTagsViewSet):
pass
class ExampleXYZView(views.ExampleTagsViewSet):
pass
class Example(views.ExampleTagsViewSet):
pass
class PascalCaseXYZTestIp(views.ExampleTagsViewSet):
pass
router = routers.SimpleRouter()
router.register('test1', ExampleIPViewSet, basename="test1")
router.register('test2', ExampleXYZView, basename="test2")
router.register('test3', Example, basename="test3")
router.register('test4', PascalCaseXYZTestIp, basename="test4")
generator = SchemaGenerator(patterns=router.urls)
schema = generator.get_schema(request=create_request('/'))
assert schema['paths']['/test1/{id}/']['get']['tags'] == ['example-ip']
assert schema['paths']['/test2/{id}/']['get']['tags'] == ['example-xyz']
assert schema['paths']['/test3/{id}/']['get']['tags'] == ['example']
assert schema['paths']['/test4/{id}/']['get']['tags'] == ['pascal-case-xyz-test-ip']
def test_auto_generated_apiview_tags(self):
class RestaurantAPIView(views.ExampleGenericAPIView):
pass

View File

@ -137,14 +137,3 @@ class ExampleValidatedAPIView(generics.GenericAPIView):
url='http://localhost', uuid=uuid.uuid4(), ip4='127.0.0.1', ip6='::1',
ip='192.168.1.1')
return Response(serializer.data)
class ExampleTagsViewSet(GenericViewSet):
serializer_class = ExampleSerializer
def retrieve(self, request, *args, **kwargs):
serializer = self.get_serializer(integer=33, string='hello', regex='foo', decimal1=3.55,
decimal2=5.33, email='a@b.co',
url='http://localhost', uuid=uuid.uuid4(), ip4='127.0.0.1', ip6='::1',
ip='192.168.1.1')
return Response(serializer.data)