Skip to content

Commit 7dd12a1

Browse files
committed
Revert "simplify relationships paths"
This reverts commit 5855b65.
1 parent 5855b65 commit 7dd12a1

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

example/tests/test_openapi.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,10 @@ def test_schema_construction():
128128
def test_schema_related_serializers():
129129
"""
130130
Confirm that paths are generated for related fields. For example:
131-
/authors/{pk}/{related_field>}
131+
url path '/authors/{pk}/{related_field>}/' generates:
132+
/authors/{id}/relationships/comments/
133+
/authors/{id}/relationships/entries/
134+
/authors/{id}/relationships/first_entry/ -- Maybe?
132135
/authors/{id}/comments/
133136
/authors/{id}/entries/
134137
/authors/{id}/first_entry/
@@ -138,7 +141,12 @@ def test_schema_related_serializers():
138141
request = create_request('/')
139142
schema = generator.get_schema(request=request)
140143
# make sure the path's relationship and related {related_field}'s got expanded
141-
assert '/authors/{id}/relationships/{related_field}' in schema['paths']
144+
assert '/authors/{id}/relationships/entries' in schema['paths']
145+
assert '/authors/{id}/relationships/comments' in schema['paths']
146+
# first_entry is a special case (SerializerMethodRelatedField)
147+
# TODO: '/authors/{id}/relationships/first_entry' supposed to be there?
148+
# It fails when doing the actual GET, so this schema excluding it is OK.
149+
# assert '/authors/{id}/relationships/first_entry/' in schema['paths']
142150
assert '/authors/{id}/comments/' in schema['paths']
143151
assert '/authors/{id}/entries/' in schema['paths']
144152
assert '/authors/{id}/first_entry/' in schema['paths']

rest_framework_json_api/schemas/openapi.py

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import warnings
22
from urllib.parse import urljoin
33

4+
from django.db.models.fields import related_descriptors as rd
45
from django.utils.module_loading import import_string as import_class_from_dotted_path
56
from rest_framework.fields import empty
67
from rest_framework.relations import ManyRelatedField
78
from rest_framework.schemas import openapi as drf_openapi
89
from rest_framework.schemas.utils import is_list_view
910

1011
from rest_framework_json_api import serializers
12+
from rest_framework_json_api.views import RelationshipView
1113

1214

1315
class SchemaGenerator(drf_openapi.SchemaGenerator):
@@ -300,7 +302,9 @@ def get_schema(self, request=None, public=False):
300302
#: - 'action' copy of current view.action (list/fetch) as this gets reset for each request.
301303
expanded_endpoints = []
302304
for path, method, view in view_endpoints:
303-
if hasattr(view, 'action') and view.action == 'retrieve_related':
305+
if isinstance(view, RelationshipView):
306+
expanded_endpoints += self._expand_relationships(path, method, view)
307+
elif hasattr(view, 'action') and view.action == 'retrieve_related':
304308
expanded_endpoints += self._expand_related(path, method, view, view_endpoints)
305309
else:
306310
expanded_endpoints.append((path, method, view, getattr(view, 'action', None)))
@@ -346,6 +350,28 @@ def get_schema(self, request=None, public=False):
346350

347351
return schema
348352

353+
def _expand_relationships(self, path, method, view):
354+
"""
355+
Expand path containing .../{id}/relationships/{related_field} into list of related fields.
356+
:return:list[tuple(path, method, view, action)]
357+
"""
358+
queryset = view.get_queryset()
359+
if not queryset.model:
360+
return [(path, method, view, getattr(view, 'action', '')), ]
361+
result = []
362+
# TODO: what about serializer-only (non-model) fields?
363+
# Shouldn't this be iterating over serializer fields rather than model fields?
364+
# Look at parent view's serializer to get the list of fields.
365+
# OR maybe like _expand_related?
366+
m = queryset.model
367+
for field in [f for f in dir(m) if not f.startswith('_')]:
368+
attr = getattr(m, field)
369+
if isinstance(attr, (rd.ReverseManyToOneDescriptor, rd.ForwardOneToOneDescriptor)):
370+
action = 'rels' if isinstance(attr, rd.ReverseManyToOneDescriptor) else 'rel'
371+
result.append((path.replace('{related_field}', field), method, view, action))
372+
373+
return result
374+
349375
def _expand_related(self, path, method, view, view_endpoints):
350376
"""
351377
Expand path containing .../{id}/{related_field} into list of related fields

0 commit comments

Comments
 (0)