Skip to content

Commit 5feb835

Browse files
OmegaDroidcarltongibson
authored andcommitted
Feature/action docs sections (#6060)
* added ability to add sections to custom action documentation * added tests to cover docs sections in custom actions * added method specific docs test for action mapping * added docs for custom action documentation
1 parent 6522d4a commit 5feb835

File tree

3 files changed

+85
-3
lines changed

3 files changed

+85
-3
lines changed

docs/topics/documenting-your-api.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,28 @@ When using viewsets, you should use the relevant action names as delimiters.
9090
Create a new user instance.
9191
"""
9292

93+
Custom actions on viewsets can also be documented in a similar way using the method names
94+
as delimiters or by attaching the documentation to action mapping methods.
95+
96+
class UserViewSet(viewsets.ModelViewset):
97+
...
98+
99+
@action(detail=False, methods=['get', 'post'])
100+
def some_action(self, request, *args, **kwargs):
101+
"""
102+
get:
103+
A description of the get method on the custom action.
104+
105+
post:
106+
A description of the post method on the custom action.
107+
"""
108+
109+
@some_action.mapping.put
110+
def put_some_action():
111+
"""
112+
A description of the put method on the custom action.
113+
"""
114+
93115

94116
### `documentation` API Reference
95117

rest_framework/schemas/inspectors.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,11 @@ def get_description(self, path, method):
247247
method_docstring = getattr(view, method_name, None).__doc__
248248
if method_docstring:
249249
# An explicit docstring on the method or action.
250-
return formatting.dedent(smart_text(method_docstring))
250+
return self._get_description_section(view, method.lower(), formatting.dedent(smart_text(method_docstring)))
251+
else:
252+
return self._get_description_section(view, getattr(view, 'action', method.lower()), view.get_view_description())
251253

252-
description = view.get_view_description()
254+
def _get_description_section(self, view, header, description):
253255
lines = [line for line in description.splitlines()]
254256
current_section = ''
255257
sections = {'': ''}
@@ -263,7 +265,6 @@ def get_description(self, path, method):
263265

264266
# TODO: SCHEMA_COERCE_METHOD_NAMES appears here and in `SchemaGenerator.get_keys`
265267
coerce_method_names = api_settings.SCHEMA_COERCE_METHOD_NAMES
266-
header = getattr(view, 'action', method.lower())
267268
if header in sections:
268269
return sections[header].strip()
269270
if header in coerce_method_names:

tests/test_schemas.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,24 @@ def get_serializer(self, *args, **kwargs):
114114
assert self.action
115115
return super(ExampleViewSet, self).get_serializer(*args, **kwargs)
116116

117+
@action(methods=['get', 'post'], detail=False)
118+
def documented_custom_action(self, request):
119+
"""
120+
get:
121+
A description of the get method on the custom action.
122+
123+
post:
124+
A description of the post method on the custom action.
125+
"""
126+
pass
127+
128+
@documented_custom_action.mapping.put
129+
def put_documented_custom_action(self, request, *args, **kwargs):
130+
"""
131+
A description of the put method on the custom action from mapping.
132+
"""
133+
pass
134+
117135

118136
if coreapi:
119137
schema_view = get_schema_view(title='Example API')
@@ -161,6 +179,13 @@ def test_anonymous_request(self):
161179
description='Custom description.',
162180
)
163181
},
182+
'documented_custom_action': {
183+
'read': coreapi.Link(
184+
url='/example/documented_custom_action/',
185+
action='get',
186+
description='A description of the get method on the custom action.',
187+
)
188+
},
164189
'read': coreapi.Link(
165190
url='/example/{id}/',
166191
action='get',
@@ -263,6 +288,33 @@ def test_authenticated_request(self):
263288
description='Deletion description.',
264289
),
265290
},
291+
'documented_custom_action': {
292+
'read': coreapi.Link(
293+
url='/example/documented_custom_action/',
294+
action='get',
295+
description='A description of the get method on the custom action.',
296+
),
297+
'create': coreapi.Link(
298+
url='/example/documented_custom_action/',
299+
action='post',
300+
description='A description of the post method on the custom action.',
301+
encoding='application/json',
302+
fields=[
303+
coreapi.Field('a', required=True, location='form', schema=coreschema.String(title='A', description='A field description')),
304+
coreapi.Field('b', required=False, location='form', schema=coreschema.String(title='B'))
305+
]
306+
),
307+
'update': coreapi.Link(
308+
url='/example/documented_custom_action/',
309+
action='put',
310+
description='A description of the put method on the custom action from mapping.',
311+
encoding='application/json',
312+
fields=[
313+
coreapi.Field('a', required=True, location='form', schema=coreschema.String(title='A', description='A field description')),
314+
coreapi.Field('b', required=False, location='form', schema=coreschema.String(title='B'))
315+
]
316+
),
317+
},
266318
'update': coreapi.Link(
267319
url='/example/{id}/',
268320
action='put',
@@ -548,6 +600,13 @@ def test_schema_for_regular_views(self):
548600
description='Custom description.',
549601
)
550602
},
603+
'documented_custom_action': {
604+
'read': coreapi.Link(
605+
url='/example1/documented_custom_action/',
606+
action='get',
607+
description='A description of the get method on the custom action.',
608+
),
609+
},
551610
'read': coreapi.Link(
552611
url='/example1/{id}/',
553612
action='get',

0 commit comments

Comments
 (0)