This commit is contained in:
Tommy Beadle 2017-06-05 22:31:45 +00:00 committed by GitHub
commit 81f138203b
7 changed files with 116 additions and 42 deletions

View File

@ -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

View File

@ -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):
"""

View File

@ -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 %}
<h2 id="{{ parent_key|add:'-' }}{{ section_key }}" class="coredocs-section-title">{{ parent_key|add:' / ' }}{{ section_key }} <a href="#{{ parent_key|add:'-' }}{{ section_key }}"><i class="fa fa-link" aria-hidden="true"></i></a></h2>
{% endif %}
{% with parent_key=parent_key|add:'-'|add:section_key section=sect %}
{% include "rest_framework/docs/document-incl.html" %}
{% endwith %}
{% endfor %}

View File

@ -14,17 +14,6 @@
</div>
</div>
{% for section_key, section in document.data|items %}
{% if section_key %}
<h2 id="{{ section_key }}" class="coredocs-section-title">{{ section_key }} <a href="#{{ section_key }}"><i class="fa fa-link" aria-hidden="true"></i>
</a></h2>
{% endif %}
{% for link_key, link in section.links|items %}
{% include "rest_framework/docs/link.html" %}
{% endfor %}
{% endfor %}
{% for link_key, link in document.links|items %}
{% include "rest_framework/docs/link.html" %}
{% endfor %}
{% with parent_key=None section=document %}
{% include "rest_framework/docs/document-incl.html" %}
{% endwith %}

View File

@ -0,0 +1,18 @@
{% load rest_framework %}
{% if section.links %}
<ul class="sub-menu {% if parent_key %}collapse{% endif %}" id="{{ parent_key }}-dropdown">
{% for link_key, link in section.links|items %}
<li><a href="#{{ parent_key }}-{{ link_key }}">{{ link.title|default:link_key }}</a></li>
{% endfor %}
</ul>
{% endif %}
{% for key, sect in section.data|items %}
<li data-toggle="collapse" data-target="#{{ parent_key|add:'-' }}{{ key }}-dropdown" class="collapsed">
<a><i class="fa fa-dot-circle-o fa-lg"></i> {{ parent_key|add:' / ' }}{% if key %}{{ key }}{% else %}API Endpoints{% endif %} <span class="arrow"></span></a>
</li>
{% with section=sect parent_key=parent_key|add:'-'|add:key %}
{% include 'rest_framework/docs/sidebar-menu.html' %}
{% endwith %}
{% endfor %}

View File

@ -1,20 +1,12 @@
{% load rest_framework %}
<div class="sidebar">
<h3 class="brand"><a href="#">{{ document.title }}</a></h3>
<i class="fa fa-bars fa-2x toggle-btn" data-toggle="collapse" data-target="#menu-content"></i>
<div class="menu-list">
<ul id="menu-content" class="menu-content collapse out">
{% for section_key, section in document.data|items %}
<li data-toggle="collapse" data-target="#{{ section_key }}-dropdown" class="collapsed">
<a><i class="fa fa-dot-circle-o fa-lg"></i> {% if section_key %}{{ section_key }}{% else %}API Endpoints{% endif %} <span class="arrow"></span></a>
</li>
<ul class="sub-menu {% if section_key %}collapse{% endif %}" id="{{ section_key }}-dropdown">
{% for link_key, link in section.links|items %}
<li><a href="#{{ section_key }}-{{ link_key }}">{{ link.title|default:link_key }}</a></li>
{% endfor %}
</ul>
{% endfor %}
{% with parent_key=None section=document %}
{% include 'rest_framework/docs/sidebar-menu.html' %}
{% endwith %}
</ul>
<ul class="menu-list menu-list-bottom">

View File

@ -55,7 +55,19 @@ class ExampleViewSet(ModelViewSet):
"""
A description of custom action.
"""
return super(ExampleSerializer, self).retrieve(self, request)
return super(ExampleViewSet, self).retrieve(self, request)
@detail_route(methods=['get', 'post'], serializer_class=EmptySerializer)
def custom_action2(self, request, pk):
"""
read: A description for getting items.
create: A description for creating items.
"""
if request.method == 'GET':
return super(ExampleViewSet, self).retrieve(self, request)
else:
return super(ExampleViewSet, self).create(self, request)
@list_route()
def custom_list_action(self, request):
@ -105,6 +117,16 @@ class TestRouterGeneratedSchema(TestCase):
coreapi.Field('ordering', required=False, location='query', schema=coreschema.String(title='Ordering', description='Which field to use when ordering the results.'))
]
),
'custom_action2': {
'read': coreapi.Link(
url='/example/{id}/custom_action2/',
action='get',
description='A description for getting items.',
fields=[
coreapi.Field('id', required=True, location='path', schema=coreschema.String()),
],
),
},
'custom_list_action': coreapi.Link(
url='/example/custom_list_action/',
action='get'
@ -173,6 +195,24 @@ class TestRouterGeneratedSchema(TestCase):
coreapi.Field('d', required=False, location='form', schema=coreschema.String(title='D')),
]
),
'custom_action2': {
'read': coreapi.Link(
url='/example/{id}/custom_action2/',
action='get',
description='A description for getting items.',
fields=[
coreapi.Field('id', required=True, location='path', schema=coreschema.String()),
],
),
'create': coreapi.Link(
url='/example/{id}/custom_action2/',
action='post',
description='A description for creating items.',
fields=[
coreapi.Field('id', required=True, location='path', schema=coreschema.String()),
],
),
},
'custom_list_action': coreapi.Link(
url='/example/custom_list_action/',
action='get'