Better descriptions for schemas

This commit is contained in:
Tom Christie 2016-10-05 16:14:23 +01:00
parent 7e3a3a4081
commit 1084dca22b
3 changed files with 71 additions and 9 deletions

View File

@ -247,6 +247,61 @@ You could then either:
One common usage of API schemas is to use them to build documentation pages.
The schema generation in REST framework uses docstrings to automatically
populate descriptions in the schema document.
These descriptions will be based on:
* The corresponding method docstring if one exists.
* A named section within the class docstring, which can be either single line or multi-line.
* The class docstring.
## Examples
An `APIView`, with an explicit method docstring.
class ListUsernames(APIView):
def get(self, request):
"""
Return a list of all user names in the system.
"""
usernames = [user.username for user in User.objects.all()]
return Response(usernames)
A `ViewSet`, with an explict action docstring.
class ListUsernames(ViewSet):
def list(self, request):
"""
Return a list of all user names in the system.
"""
usernames = [user.username for user in User.objects.all()]
return Response(usernames)
A generic view with sections in the class docstring, using single-line style.
class UserList(generics.ListCreateAPIView):
"""
get: Create a new user.
post: List all the users.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsAdminUser,)
A generic viewset with sections in the class docstring, using multi-line style.
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
retrieve:
Return a user instance.
list:
Return all users, ordered by most recently joined.
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
---

View File

@ -5,7 +5,7 @@ from importlib import import_module
from django.conf import settings
from django.contrib.admindocs.views import simplify_regex
from django.utils import six
from django.utils.encoding import force_text
from django.utils.encoding import force_text, smart_text
from rest_framework import exceptions, renderers, serializers
from rest_framework.compat import (
@ -14,6 +14,7 @@ from rest_framework.compat import (
from rest_framework.request import clone_request
from rest_framework.response import Response
from rest_framework.settings import api_settings
from rest_framework.utils import formatting
from rest_framework.views import APIView
header_regex = re.compile('^[a-zA-Z][0-9A-Za-z_]*:')
@ -297,15 +298,17 @@ class SchemaGenerator(object):
"""
Determine a link description.
This with either be the class docstring, or a specific section for it.
For views, use method names, eg `get:` to introduce a section.
For viewsets, use action names, eg `retrieve:` to introduce a section.
The section names will correspond to the methods on the class.
This will be based on the method docstring if one exists,
or else the class docstring.
"""
view_description = view.get_view_description()
lines = [line.strip() for line in view_description.splitlines()]
method_name = getattr(view, 'action', method.lower())
method_docstring = getattr(view, method_name, None).__doc__
if method_docstring:
# An explicit docstring on the method or action.
return formatting.dedent(smart_text(method_docstring))
description = view.get_view_description()
lines = [line.strip() for line in description.splitlines()]
current_section = ''
sections = {'': ''}

View File

@ -46,6 +46,9 @@ class ExampleViewSet(ModelViewSet):
@detail_route(methods=['post'], serializer_class=AnotherSerializer)
def custom_action(self, request, pk):
"""
A description of custom action.
"""
return super(ExampleSerializer, self).retrieve(self, request)
@list_route()
@ -149,6 +152,7 @@ class TestRouterGeneratedSchema(TestCase):
url='/example/{pk}/custom_action/',
action='post',
encoding='application/json',
description='A description of custom action.',
fields=[
coreapi.Field('pk', required=True, location='path'),
coreapi.Field('c', required=True, location='form'),