mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 17:47:04 +03:00
Merge pull request #5334 from Woile/woile-nested-docs-fix
Fix docs multiple nested and multiple methods
This commit is contained in:
commit
4d5e846ca7
|
@ -2,6 +2,14 @@ var responseDisplay = 'data'
|
|||
var coreapi = window.coreapi
|
||||
var schema = window.schema
|
||||
|
||||
function normalizeKeys (arr) {
|
||||
var _normarr = [];
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
_normarr = _normarr.concat(arr[i].split(' > '));
|
||||
}
|
||||
return _normarr;
|
||||
}
|
||||
|
||||
function normalizeHTTPHeader (str) {
|
||||
// Capitalize HTTP headers for display.
|
||||
return (str.charAt(0).toUpperCase() + str.substring(1))
|
||||
|
@ -94,7 +102,7 @@ $(function () {
|
|||
var $requestAwaiting = $form.find('.request-awaiting')
|
||||
var $responseRaw = $form.find('.response-raw')
|
||||
var $responseData = $form.find('.response-data')
|
||||
var key = $form.data('key')
|
||||
var key = normalizeKeys($form.data('key'))
|
||||
var params = {}
|
||||
var entries = formEntries($form.get()[0])
|
||||
|
||||
|
@ -212,7 +220,6 @@ $(function () {
|
|||
}
|
||||
|
||||
var client = new coreapi.Client(options)
|
||||
|
||||
client.action(schema, key, params).then(function (data) {
|
||||
var response = JSON.stringify(data, null, 2)
|
||||
$requestAwaiting.addClass('hide')
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
</a></h2>
|
||||
{% endif %}
|
||||
|
||||
{% for link_key, link in section.links|items %}
|
||||
{% for link_key, link in section|schema_links|items %}
|
||||
{% include "rest_framework/docs/link.html" %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% load rest_framework %}
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade api-modal" id="{{ section_key }}_{{ link_key }}_modal" tabindex="-1" role="dialog" aria-labelledby="api explorer modal">
|
||||
<div class="modal fade api-modal" id="{{ section_key }}_{{ link_key|slugify }}_modal" tabindex="-1" role="dialog" aria-labelledby="api explorer modal">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
class="btn btn-sm btn-success"
|
||||
style="float: right; margin-top: 20px"
|
||||
data-toggle="modal"
|
||||
data-target="#{{ section_key }}_{{ link_key }}_modal">
|
||||
data-target="#{{ section_key }}_{{ link_key|slugify }}_modal">
|
||||
<i class="fa fa-exchange"></i> Interact
|
||||
</button>
|
||||
|
||||
<h3 id="{{ section_key }}-{{ link_key }}" class="coredocs-link-title">{{ link.title|default:link_key }} <a href="#{{ section_key }}-{{ link_key }}"><i class="fa fa-link" aria-hidden="true"></i>
|
||||
<h3 id="{{ section_key }}-{{ link_key|slugify }}" class="coredocs-link-title">{{ link.title|default:link_key }} <a href="#{{ section_key }}-{{ link_key|slugify }}"><i class="fa fa-link" aria-hidden="true"></i>
|
||||
</a></h3>
|
||||
|
||||
<div class="meta">
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
<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>
|
||||
<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>
|
||||
{% for link_key, link in section|schema_links|items %}
|
||||
<li><a href="#{{ section_key }}-{{ link_key|slugify }}">{{ link.title|default:link_key }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
|
|
|
@ -244,6 +244,29 @@ def items(value):
|
|||
return value.items()
|
||||
|
||||
|
||||
@register.filter
|
||||
def schema_links(section, sec_key=None):
|
||||
"""
|
||||
Recursively find every link in a schema, even nested.
|
||||
"""
|
||||
NESTED_FORMAT = '%s > %s' # this format is used in docs/js/api.js:normalizeKeys
|
||||
links = section.links
|
||||
if section.data:
|
||||
data = section.data.items()
|
||||
for sub_section_key, sub_section in data:
|
||||
new_links = schema_links(sub_section, sec_key=sub_section_key)
|
||||
links.update(new_links)
|
||||
|
||||
if sec_key is not None:
|
||||
new_links = OrderedDict()
|
||||
for link_key, link in links.items():
|
||||
new_key = NESTED_FORMAT % (sec_key, link_key)
|
||||
new_links.update({new_key: link})
|
||||
return new_links
|
||||
|
||||
return links
|
||||
|
||||
|
||||
@register.filter
|
||||
def add_nested_class(value):
|
||||
if isinstance(value, dict):
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
# encoding: utf-8
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from rest_framework.compat import coreapi, coreschema
|
||||
from rest_framework.relations import Hyperlink
|
||||
from rest_framework.templatetags import rest_framework
|
||||
from rest_framework.templatetags.rest_framework import (
|
||||
add_nested_class, add_query_param, as_string, break_long_headers,
|
||||
format_value, get_pagination_html, urlize_quoted_links
|
||||
format_value, get_pagination_html, schema_links, urlize_quoted_links
|
||||
)
|
||||
from rest_framework.test import APIRequestFactory
|
||||
|
||||
|
@ -300,3 +303,313 @@ class URLizerTests(TestCase):
|
|||
data['"foo_set": [\n "http://api/foos/1/"\n], '] = \
|
||||
'"foo_set": [\n "<a href="http://api/foos/1/">http://api/foos/1/</a>"\n], '
|
||||
self._urlize_dict_check(data)
|
||||
|
||||
|
||||
@unittest.skipUnless(coreapi, 'coreapi is not installed')
|
||||
class SchemaLinksTests(TestCase):
|
||||
|
||||
def test_schema_with_empty_links(self):
|
||||
schema = coreapi.Document(
|
||||
url='',
|
||||
title='Example API',
|
||||
content={
|
||||
'users': {
|
||||
'list': {}
|
||||
}
|
||||
}
|
||||
)
|
||||
section = schema['users']
|
||||
flat_links = schema_links(section)
|
||||
assert len(flat_links) is 0
|
||||
|
||||
def test_single_action(self):
|
||||
schema = coreapi.Document(
|
||||
url='',
|
||||
title='Example API',
|
||||
content={
|
||||
'users': {
|
||||
'list': coreapi.Link(
|
||||
url='/users/',
|
||||
action='get',
|
||||
fields=[]
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
section = schema['users']
|
||||
flat_links = schema_links(section)
|
||||
assert len(flat_links) is 1
|
||||
assert 'list' in flat_links
|
||||
|
||||
def test_default_actions(self):
|
||||
schema = coreapi.Document(
|
||||
url='',
|
||||
title='Example API',
|
||||
content={
|
||||
'users': {
|
||||
'create': coreapi.Link(
|
||||
url='/users/',
|
||||
action='post',
|
||||
fields=[]
|
||||
),
|
||||
'list': coreapi.Link(
|
||||
url='/users/',
|
||||
action='get',
|
||||
fields=[]
|
||||
),
|
||||
'read': coreapi.Link(
|
||||
url='/users/{id}/',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
),
|
||||
'update': coreapi.Link(
|
||||
url='/users/{id}/',
|
||||
action='patch',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
section = schema['users']
|
||||
flat_links = schema_links(section)
|
||||
assert len(flat_links) is 4
|
||||
assert 'list' in flat_links
|
||||
assert 'create' in flat_links
|
||||
assert 'read' in flat_links
|
||||
assert 'update' in flat_links
|
||||
|
||||
def test_default_actions_and_single_custom_action(self):
|
||||
schema = coreapi.Document(
|
||||
url='',
|
||||
title='Example API',
|
||||
content={
|
||||
'users': {
|
||||
'create': coreapi.Link(
|
||||
url='/users/',
|
||||
action='post',
|
||||
fields=[]
|
||||
),
|
||||
'list': coreapi.Link(
|
||||
url='/users/',
|
||||
action='get',
|
||||
fields=[]
|
||||
),
|
||||
'read': coreapi.Link(
|
||||
url='/users/{id}/',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
),
|
||||
'update': coreapi.Link(
|
||||
url='/users/{id}/',
|
||||
action='patch',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
),
|
||||
'friends': coreapi.Link(
|
||||
url='/users/{id}/friends',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
section = schema['users']
|
||||
flat_links = schema_links(section)
|
||||
assert len(flat_links) is 5
|
||||
assert 'list' in flat_links
|
||||
assert 'create' in flat_links
|
||||
assert 'read' in flat_links
|
||||
assert 'update' in flat_links
|
||||
assert 'friends' in flat_links
|
||||
|
||||
def test_default_actions_and_single_custom_action_two_methods(self):
|
||||
schema = coreapi.Document(
|
||||
url='',
|
||||
title='Example API',
|
||||
content={
|
||||
'users': {
|
||||
'create': coreapi.Link(
|
||||
url='/users/',
|
||||
action='post',
|
||||
fields=[]
|
||||
),
|
||||
'list': coreapi.Link(
|
||||
url='/users/',
|
||||
action='get',
|
||||
fields=[]
|
||||
),
|
||||
'read': coreapi.Link(
|
||||
url='/users/{id}/',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
),
|
||||
'update': coreapi.Link(
|
||||
url='/users/{id}/',
|
||||
action='patch',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
),
|
||||
'friends': {
|
||||
'list': coreapi.Link(
|
||||
url='/users/{id}/friends',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
),
|
||||
'create': coreapi.Link(
|
||||
url='/users/{id}/friends',
|
||||
action='post',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
section = schema['users']
|
||||
flat_links = schema_links(section)
|
||||
assert len(flat_links) is 6
|
||||
assert 'list' in flat_links
|
||||
assert 'create' in flat_links
|
||||
assert 'read' in flat_links
|
||||
assert 'update' in flat_links
|
||||
assert 'friends > list' in flat_links
|
||||
assert 'friends > create' in flat_links
|
||||
|
||||
def test_multiple_nested_routes(self):
|
||||
schema = coreapi.Document(
|
||||
url='',
|
||||
title='Example API',
|
||||
content={
|
||||
'animals': {
|
||||
'dog': {
|
||||
'vet': {
|
||||
'list': coreapi.Link(
|
||||
url='/animals/dog/{id}/vet',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
)
|
||||
},
|
||||
'read': coreapi.Link(
|
||||
url='/animals/dog/{id}',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
)
|
||||
},
|
||||
'cat': {
|
||||
'list': coreapi.Link(
|
||||
url='/animals/cat/',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
),
|
||||
'create': coreapi.Link(
|
||||
url='/aniamls/cat',
|
||||
action='post',
|
||||
fields=[]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
section = schema['animals']
|
||||
flat_links = schema_links(section)
|
||||
assert len(flat_links) is 4
|
||||
assert 'cat > create' in flat_links
|
||||
assert 'cat > list' in flat_links
|
||||
assert 'dog > read' in flat_links
|
||||
assert 'dog > vet > list' in flat_links
|
||||
|
||||
def test_multiple_resources_with_multiple_nested_routes(self):
|
||||
schema = coreapi.Document(
|
||||
url='',
|
||||
title='Example API',
|
||||
content={
|
||||
'animals': {
|
||||
'dog': {
|
||||
'vet': {
|
||||
'list': coreapi.Link(
|
||||
url='/animals/dog/{id}/vet',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
)
|
||||
},
|
||||
'read': coreapi.Link(
|
||||
url='/animals/dog/{id}',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
)
|
||||
},
|
||||
'cat': {
|
||||
'list': coreapi.Link(
|
||||
url='/animals/cat/',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
),
|
||||
'create': coreapi.Link(
|
||||
url='/aniamls/cat',
|
||||
action='post',
|
||||
fields=[]
|
||||
)
|
||||
}
|
||||
},
|
||||
'farmers': {
|
||||
'silo': {
|
||||
'soy': {
|
||||
'list': coreapi.Link(
|
||||
url='/farmers/silo/{id}/soy',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
)
|
||||
},
|
||||
'list': coreapi.Link(
|
||||
url='/farmers/silo',
|
||||
action='get',
|
||||
fields=[
|
||||
coreapi.Field('id', required=True, location='path', schema=coreschema.String())
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
section = schema['animals']
|
||||
flat_links = schema_links(section)
|
||||
assert len(flat_links) is 4
|
||||
assert 'cat > create' in flat_links
|
||||
assert 'cat > list' in flat_links
|
||||
assert 'dog > read' in flat_links
|
||||
assert 'dog > vet > list' in flat_links
|
||||
|
||||
section = schema['farmers']
|
||||
flat_links = schema_links(section)
|
||||
assert len(flat_links) is 2
|
||||
assert 'silo > list' in flat_links
|
||||
assert 'silo > soy > list' in flat_links
|
||||
|
|
Loading…
Reference in New Issue
Block a user