Skip to content

Commit 5a43d41

Browse files
author
Maxence
committed
Recursive include is now called with "only"
Use of a dictionnary { serializer: fields } for recursive call of __get_fields__
1 parent 34f9683 commit 5a43d41

File tree

6 files changed

+87
-77
lines changed

6 files changed

+87
-77
lines changed

Diff for: rest_framework_docs/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
__version__ = '0.0.5'
2+
3+
SERIALIZER_FIELDS = {}

Diff for: rest_framework_docs/api_docs.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from django.conf import settings
33
from django.core.urlresolvers import RegexURLResolver, RegexURLPattern
44
from rest_framework.views import APIView
5+
6+
from rest_framework_docs import SERIALIZER_FIELDS
57
from rest_framework_docs.api_endpoint import ApiEndpoint
68

79

@@ -11,6 +13,7 @@ def __init__(self, filter_param=None):
1113
"""
1214
:param filter_param: namespace or app_name
1315
"""
16+
SERIALIZER_FIELDS.clear()
1417
self.endpoints = []
1518
root_urlconf = __import__(settings.ROOT_URLCONF)
1619
if hasattr(root_urlconf, 'urls'):
@@ -32,4 +35,4 @@ def _is_drf_view(self, pattern):
3235
return hasattr(pattern.callback, 'cls') and issubclass(pattern.callback.cls, APIView)
3336

3437
def get_endpoints(self):
35-
return sorted(self.endpoints, key=attrgetter('name'))
38+
return sorted(self.endpoints, key=attrgetter('name', 'path'))

Diff for: rest_framework_docs/api_endpoint.py

+5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from django.contrib.admindocs.views import simplify_regex
44
from rest_framework import serializers
55
from rest_framework.viewsets import ModelViewSet
6+
from rest_framework_docs import SERIALIZER_FIELDS
67

78

89
class ApiEndpoint(object):
@@ -25,6 +26,7 @@ def __init__(self, pattern, parent_pattern=None):
2526
self.path = self.__get_path__(parent_pattern)
2627
self.allowed_methods = self.__get_allowed_methods__()
2728
self.errors = None
29+
self.nb_recurse = 0
2830
self.fields = self.__get_serializer_fields__()
2931
self.fields_json = self.__get_serializer_fields_json__()
3032
self.permissions = self.__get_permissions_class__()
@@ -62,6 +64,8 @@ def __get_serializer_fields__(self):
6264
return fields
6365

6466
def __get_fields__(self, serializer):
67+
if serializer in SERIALIZER_FIELDS:
68+
return SERIALIZER_FIELDS.get(serializer)
6569
fields = []
6670
for key, field in serializer().get_fields().items():
6771
item = dict(
@@ -77,6 +81,7 @@ def __get_fields__(self, serializer):
7781
elif isinstance(field, serializers.Serializer):
7882
item['fields'] = self.__get_fields__(field.__class__)
7983
fields.append(item)
84+
SERIALIZER_FIELDS[serializer] = fields
8085
return fields
8186

8287
def __get_serializer_fields_json__(self):

Diff for: rest_framework_docs/templates/rest_framework_docs/fields.html

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
<ul class="list fields">
22
{% for field in item.fields %}
33
<li class="field">
4-
{{ field.name }}: {{ field.type }} {% if field.required %}<span class="label label-primary label-required"
5-
title="Required">R</span>{% endif %}
4+
{{ field.name }}: {{ field.type }}
5+
{% if field.required %}<span class="label label-primary label-required" title="Required">R</span>{% endif %}
66
{% if field.sub_type %} ({{ field.sub_type }}) {% endif %}
77
{% if field.fields %}
8-
{% with field as item %}
9-
{% include 'rest_framework_docs/fields.html' %}
10-
{% endwith %}
8+
{% include 'rest_framework_docs/fields.html' with item=field only %}
119
{% endif %}
1210
</li>
1311
{% endfor %}

Diff for: rest_framework_docs/templates/rest_framework_docs/home.html

+71-69
Original file line numberDiff line numberDiff line change
@@ -3,102 +3,104 @@
33
{% block apps_menu %}
44
{% regroup endpoints by labels as endpoints_grouped %}
55
{% if endpoints_grouped|length > 1 %}
6-
<li class="dropdown">
7-
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Jump To <span class="caret"></span></a>
6+
<li class="dropdown">
7+
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Jump
8+
To <span class="caret"></span></a>
89
<ul class="dropdown-menu">
9-
{% for group in endpoints_grouped %}
10+
{% for group in endpoints_grouped %}
1011
<li><a href="#{{ group.grouper.name|slugify }}-group">{{ group.grouper.name }}</a></li>
11-
{% endfor %}
12+
{% endfor %}
1213
</ul>
13-
</li>
14+
</li>
1415
{% endif %}
1516
{% endblock %}
1617

1718

1819
{% block content %}
19-
{% regroup endpoints by labels as endpoints_grouped %}
20-
{% if endpoints_grouped %}
21-
{% for group in endpoints_grouped %}
22-
<h1 id="{{ group.grouper.name|slugify }}-group">
23-
{% if group.grouper.parent %}
24-
<a href="{% url 'drfdocs-filter' group.grouper.parent %}">{{ group.grouper.name }}</a>
25-
{% endif %}
26-
</h1>
20+
{% regroup endpoints by labels as endpoints_grouped %}
21+
{% if endpoints_grouped %}
22+
{% for group in endpoints_grouped %}
23+
<h1 id="{{ group.grouper.name|slugify }}-group">
24+
{% if group.grouper.parent %}
25+
<a href="{% url 'drfdocs-filter' group.grouper.parent %}">{{ group.grouper.name }}</a>
26+
{% endif %}
27+
</h1>
2728

28-
<div class="panel-group" role="tablist">
29+
<div class="panel-group" role="tablist">
2930

3031
{% for endpoint in group.list %}
3132

32-
<div class="panel panel-default endpoint">
33+
<div class="panel panel-default endpoint">
3334

3435
<div class="panel-heading" role="tab" data-toggle="collapse" data-target="#{{ endpoint.path|slugify }}">
35-
<div class="row">
36-
<div class="col-md-7">
37-
<h4 class="panel-title title">
38-
<i class="fa fa-link"></i> {{ endpoint.path }}
39-
</h4>
40-
</div>
36+
<div class="row">
37+
<div class="col-md-7">
38+
<h4 class="panel-title title">
39+
<i class="fa fa-link"></i> {{ endpoint.path }}
40+
</h4>
41+
</div>
4142

42-
<div class="col-md-5">
43-
<ul class="list-inline methods">
44-
{% for method in endpoint.allowed_methods %}
45-
<li class="method {{ method|lower }}">{{ method }}</li>
46-
{% endfor %}
47-
<li class="method plug"
48-
data-toggle="modal"
49-
data-path="{{ endpoint.path }}"
50-
data-methods="{{ endpoint.allowed_methods }}"
51-
data-permissions="{{ endpoint.permissions }}"
52-
data-fields="{{ endpoint.fields_json }}">
53-
<i class="fa fa-plug"></i></li>
54-
</ul>
43+
<div class="col-md-5">
44+
<ul class="list-inline methods">
45+
{% for method in endpoint.allowed_methods %}
46+
<li class="method {{ method|lower }}">{{ method }}</li>
47+
{% endfor %}
48+
<li class="method plug"
49+
data-toggle="modal"
50+
data-path="{{ endpoint.path }}"
51+
data-methods="{{ endpoint.allowed_methods }}"
52+
data-permissions="{{ endpoint.permissions }}"
53+
data-fields="{{ endpoint.fields_json }}">
54+
<i class="fa fa-plug"></i></li>
55+
</ul>
56+
</div>
5557
</div>
56-
</div>
5758
</div>
5859

5960
<div id="{{ endpoint.path|slugify }}" class="panel-collapse collapse" role="tabpanel">
60-
<div class="panel-body">
61-
{% if endpoint.docstring %}
62-
<p class="lead">{{ endpoint.docstring }}</p>
63-
{% endif %}
61+
<div class="panel-body">
62+
{% if endpoint.docstring %}
63+
<p class="lead">{{ endpoint.docstring }}</p>
64+
{% endif %}
6465

65-
{% if endpoint.errors %}
66-
<div class="alert alert-danger" role="alert">Oops! There was something wrong with {{ endpoint.errors }}. Please check your code.</div>
67-
{% endif %}
68-
{% if endpoint.fields %}
69-
<p class="fields-desc">Fields:</p>
70-
{% with endpoint as item %}
71-
{% include 'rest_framework_docs/fields.html' %}
72-
{% endwith %}
73-
{% elif not endpoint.errors %}
74-
<p>No fields.</p>
75-
{% endif %}
76-
</div>
66+
{% if endpoint.errors %}
67+
<div class="alert alert-danger" role="alert">Oops! There was something wrong with {{ endpoint.errors }}.
68+
Please check your code.
69+
</div>
70+
{% endif %}
71+
{% if endpoint.fields %}
72+
<p class="fields-desc">Fields:</p>
73+
{% include 'rest_framework_docs/fields.html' with item=endpoint only %}
74+
{% elif not endpoint.errors %}
75+
<p>No fields.</p>
76+
{% endif %}
77+
</div>
7778
</div>
78-
</div>
79+
</div>
7980
{% endfor %}
8081

81-
</div>
82+
</div>
8283

83-
{% endfor %}
84-
{% elif not query %}
85-
<h2 class="text-center">There are currently no api endpoints to document.</h2>
86-
{% else %}
87-
<h2 class="text-center">No endpoints found for {{ query }}.</h2>
88-
{% endif %}
84+
{% endfor %}
85+
{% elif not query %}
86+
<h2 class="text-center">There are currently no api endpoints to document.</h2>
87+
{% else %}
88+
<h2 class="text-center">No endpoints found for {{ query }}.</h2>
89+
{% endif %}
8990

90-
<!-- Modal -->
91-
<div class="modal fade api-modal" id="liveAPIModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
91+
<!-- Modal -->
92+
<div class="modal fade api-modal" id="liveAPIModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
9293
<div class="modal-dialog modal-lg" role="document">
93-
<div class="modal-content">
94-
<div class="modal-header">
95-
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
96-
<h4 class="modal-title">Live API Endpoints <span class="label label-info">Beta</span></h4>
97-
</div>
94+
<div class="modal-content">
95+
<div class="modal-header">
96+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
97+
aria-hidden="true">&times;</span></button>
98+
<h4 class="modal-title">Live API Endpoints <span class="label label-info">Beta</span></h4>
99+
</div>
98100

99-
<div id="liveAPIEndpoints"></div>
100-
</div>
101+
<div id="liveAPIEndpoints"></div>
102+
</div>
101103
</div>
102-
</div>
104+
</div>
103105

104106
{% endblock %}

Diff for: tests/tests.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def test_index_view_with_endpoints(self):
3939
self.assertTrue(response.context["endpoints"][1].fields[0]["required"])
4040

4141
# The view "OrganisationErroredView" (organisations/(?P<slug>[\w-]+)/errored/) should contain an error.
42-
self.assertEqual(str(response.context["endpoints"][9].errors), "'test_value'")
42+
self.assertEqual(str(response.context["endpoints"][7].errors), "'test_value'")
4343

4444
def test_index_search_with_endpoints(self):
4545
response = self.client.get("%s?search=reset-password" % reverse("drfdocs"))
@@ -81,7 +81,7 @@ def test_index_view_with_existent_namespace(self):
8181
self.assertEqual(len(response.context["endpoints"]), 3)
8282

8383
# The view "OrganisationErroredView" (organisations/(?P<slug>[\w-]+)/errored/) should contain an error.
84-
self.assertEqual(str(response.context["endpoints"][2].errors), "'test_value'")
84+
self.assertEqual(str(response.context["endpoints"][0].errors), "'test_value'")
8585

8686
# Test 'members' namespace
8787
response = self.client.get(reverse('drfdocs-filter', args=['members']))

0 commit comments

Comments
 (0)