diff --git a/docs/topics/documenting-your-api.md b/docs/topics/documenting-your-api.md index 9a87c17c1..d73a13ab5 100644 --- a/docs/topics/documenting-your-api.md +++ b/docs/topics/documenting-your-api.md @@ -69,6 +69,20 @@ When using viewsets, you should use the relevant action names as delimiters. Create a new user instance. """ +When using the `@detail_route` or `@list_route` decorators, the docstring for +the decorated method may use the `action:` style delimiters. + + class UserViewSet(viewsets.ModelViewSet): + @detail_route(methods=('get', 'post')) + def groups(self, request, pk=None): + """ + retrieve: + Return the groups for the given user. + + create: + Add the user to a new group. + """ + --- ## Third party packages diff --git a/rest_framework/schemas.py b/rest_framework/schemas.py index 875f9454b..2230656e1 100644 --- a/rest_framework/schemas.py +++ b/rest_framework/schemas.py @@ -8,7 +8,7 @@ from django.core.exceptions import PermissionDenied from django.db import models from django.http import Http404 from django.utils import six -from django.utils.encoding import force_text, smart_text +from django.utils.encoding import force_text from django.utils.translation import ugettext_lazy as _ from rest_framework import exceptions, renderers, serializers @@ -19,7 +19,6 @@ 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.utils.model_meta import _get_pk from rest_framework.views import APIView @@ -469,31 +468,36 @@ class SchemaGenerator(object): This will be based on the method docstring if one exists, or else the class docstring. """ - method_name = getattr(view, 'action', method.lower()) - method_docstring = getattr(view, method_name, None).__doc__ - if method_docstring: + method = method.lower() + method_name = getattr(view, 'action', method) + view_method = getattr(view, method_name, None) + description = None + if view_method: # An explicit docstring on the method or action. - return formatting.dedent(smart_text(method_docstring)) - - description = view.get_view_description() + description = api_settings.VIEW_DESCRIPTION_FUNCTION(view_method) + if not description: + description = view.get_view_description() lines = [line.strip() for line in description.splitlines()] current_section = '' sections = {'': ''} for line in lines: if header_regex.match(line): - current_section, seperator, lead = line.partition(':') + current_section, separator, lead = line.partition(':') sections[current_section] = lead.strip() else: sections[current_section] += '\n' + line - header = getattr(view, 'action', method.lower()) - if header in sections: - return sections[header].strip() - if header in self.coerce_method_names: - if self.coerce_method_names[header] in sections: - return sections[self.coerce_method_names[header]].strip() - return sections[''].strip() + section_name = '' + for attempt in (method_name, self.default_mapping.get(method, method)): + if attempt in sections: + section_name = attempt + break + if self.coerce_method_names.get(attempt) in sections: + section_name = self.coerce_method_names[attempt] + break + + return sections[section_name].strip() def get_encoding(self, path, method, view): """ diff --git a/rest_framework/templates/rest_framework/docs/document-incl.html b/rest_framework/templates/rest_framework/docs/document-incl.html new file mode 100644 index 000000000..bb2020364 --- /dev/null +++ b/rest_framework/templates/rest_framework/docs/document-incl.html @@ -0,0 +1,17 @@ +{% load rest_framework %} + +{% for link_key, link in section.links|items %} + {% with section_key=parent_key %} + {% include "rest_framework/docs/link.html" %} + {% endwith %} +{% endfor %} + +{% for section_key, sect in section.data|items %} + {% if section_key %} +