Skip to content

Commit b96d79d

Browse files
committed
Merge branch 'develop' of github.com:django-json-api/django-rest-framework-json-api into jarekwg-optimize/relationship-extraction
2 parents 04a100c + 0aedffb commit b96d79d

File tree

3 files changed

+122
-108
lines changed

3 files changed

+122
-108
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ pip-delete-this-directory.txt
2828
# Pycharm project files
2929
.idea/
3030

31+
# PyTest cache
32+
.cache/
33+
3134
# Tox
3235
.tox/
3336

rest_framework_json_api/renderers.py

+54-72
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
from collections import OrderedDict
66

77
import inflection
8+
from django.db.models import Manager, QuerySet
89
from django.utils import six, encoding
910
from rest_framework import relations
1011
from rest_framework import renderers
11-
from rest_framework.serializers import BaseSerializer, ListSerializer, ModelSerializer
12+
from rest_framework.serializers import BaseSerializer, Serializer, ListSerializer
1213
from rest_framework.settings import api_settings
1314

1415
from . import utils
@@ -87,24 +88,18 @@ def extract_relationships(fields, resource, resource_instance):
8788
continue
8889

8990
source = field.source
90-
serializer_method = getattr(field.parent, source, None)
9191
relation_type = utils.get_related_resource_type(field)
9292

9393
if isinstance(field, relations.HyperlinkedIdentityField):
94-
try:
95-
relation_instance_or_manager = getattr(resource_instance, source)
96-
except AttributeError:
97-
if serializer_method and hasattr(serializer_method, '__call__'):
98-
relation_instance_or_manager = serializer_method(resource_instance)
99-
else:
100-
continue
101-
94+
resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
95+
if not resolved:
96+
continue
10297
# special case for HyperlinkedIdentityField
10398
relation_data = list()
10499

105100
# Don't try to query an empty relation
106-
relation_queryset = relation_instance_or_manager.all() \
107-
if relation_instance_or_manager is not None else list()
101+
relation_queryset = relation_instance \
102+
if relation_instance is not None else list()
108103

109104
for related_object in relation_queryset:
110105
relation_data.append(
@@ -122,13 +117,9 @@ def extract_relationships(fields, resource, resource_instance):
122117
continue
123118

124119
if isinstance(field, ResourceRelatedField):
125-
try:
126-
relation_instance_or_manager = getattr(resource_instance, source)
127-
except AttributeError:
128-
if serializer_method and hasattr(serializer_method, '__call__'):
129-
relation_instance_or_manager = serializer_method(resource_instance)
130-
else:
131-
continue
120+
resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
121+
if not resolved:
122+
continue
132123

133124
# special case for ResourceRelatedField
134125
relation_data = {
@@ -144,14 +135,9 @@ def extract_relationships(fields, resource, resource_instance):
144135
continue
145136

146137
if isinstance(field, (relations.PrimaryKeyRelatedField, relations.HyperlinkedRelatedField)):
147-
try:
148-
relation = getattr(resource_instance, '%s_id' % field.source)
149-
except AttributeError:
150-
if serializer_method and hasattr(serializer_method, '__call__'):
151-
relation = serializer_method(resource_instance).pk
152-
else:
153-
continue
154-
138+
resolved, relation = utils.get_relation_instance(resource_instance, '%s_id' % source, field.parent)
139+
if not resolved:
140+
continue
155141
relation_id = relation if resource.get(field_name) else None
156142
relation_data = {
157143
'data': (
@@ -167,13 +153,9 @@ def extract_relationships(fields, resource, resource_instance):
167153
continue
168154

169155
if isinstance(field, relations.ManyRelatedField):
170-
try:
171-
relation_instance_or_manager = getattr(resource_instance, source)
172-
except AttributeError:
173-
if serializer_method and hasattr(serializer_method, '__call__'):
174-
relation_instance_or_manager = serializer_method(resource_instance)
175-
else:
176-
continue
156+
resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
157+
if not resolved:
158+
continue
177159

178160
if isinstance(field.child_relation, ResourceRelatedField):
179161
# special case for ResourceRelatedField
@@ -197,11 +179,15 @@ def extract_relationships(fields, resource, resource_instance):
197179
continue
198180

199181
relation_data = list()
200-
for related_object in relation_instance_or_manager.all():
201-
related_object_type = utils.get_instance_or_manager_resource_type(related_object)
182+
for nested_resource_instance in relation_instance:
183+
nested_resource_instance_type = (
184+
relation_type or
185+
utils.get_resource_type_from_instance(nested_resource_instance)
186+
)
187+
202188
relation_data.append(OrderedDict([
203-
('type', related_object_type),
204-
('id', encoding.force_text(related_object.pk))
189+
('type', nested_resource_instance_type),
190+
('id', encoding.force_text(nested_resource_instance.pk))
205191
]))
206192
data.update({
207193
field_name: {
@@ -213,23 +199,23 @@ def extract_relationships(fields, resource, resource_instance):
213199
})
214200
continue
215201

216-
if isinstance(field, ListSerializer):
217-
try:
218-
relation_instance_or_manager = getattr(resource_instance, source)
219-
except AttributeError:
220-
if serializer_method and hasattr(serializer_method, '__call__'):
221-
relation_instance_or_manager = serializer_method(resource_instance)
222-
else:
223-
continue
202+
if isinstance(field, ListSerializer) and relation_instance is not None:
203+
resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
204+
if not resolved:
205+
continue
224206

225207
relation_data = list()
226208

227209
serializer_data = resource.get(field_name)
228-
resource_instance_queryset = list(relation_instance_or_manager.all())
210+
resource_instance_queryset = list(relation_instance)
229211
if isinstance(serializer_data, list):
230212
for position in range(len(serializer_data)):
231213
nested_resource_instance = resource_instance_queryset[position]
232-
nested_resource_instance_type = utils.get_resource_type_from_instance(nested_resource_instance)
214+
nested_resource_instance_type = (
215+
relation_type or
216+
utils.get_resource_type_from_instance(nested_resource_instance)
217+
)
218+
233219
relation_data.append(OrderedDict([
234220
('type', nested_resource_instance_type),
235221
('id', encoding.force_text(nested_resource_instance.pk))
@@ -238,24 +224,17 @@ def extract_relationships(fields, resource, resource_instance):
238224
data.update({field_name: {'data': relation_data}})
239225
continue
240226

241-
if isinstance(field, ModelSerializer):
242-
try:
243-
relation_instance_or_manager = getattr(resource_instance, source)
244-
except AttributeError:
245-
if serializer_method and hasattr(serializer_method, '__call__'):
246-
relation_instance_or_manager = serializer_method(resource_instance)
247-
else:
248-
continue
249-
250-
relation_model = field.Meta.model
251-
relation_type = utils.format_resource_type(relation_model.__name__)
227+
if isinstance(field, Serializer):
228+
resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
229+
if not resolved:
230+
continue
252231

253232
data.update({
254233
field_name: {
255234
'data': (
256235
OrderedDict([
257236
('type', relation_type),
258-
('id', encoding.force_text(relation_instance_or_manager.pk))
237+
('id', encoding.force_text(relation_instance.pk))
259238
]) if resource.get(field_name) else None)
260239
}
261240
})
@@ -294,38 +273,41 @@ def extract_included(fields, resource, resource_instance, included_resources):
294273
continue
295274

296275
try:
297-
relation_instance_or_manager = getattr(resource_instance, field_name)
276+
relation_instance = getattr(resource_instance, field_name)
298277
except AttributeError:
299278
try:
300279
# For ManyRelatedFields if `related_name` is not set we need to access `foo_set` from `source`
301-
relation_instance_or_manager = getattr(resource_instance, field.child_relation.source)
280+
relation_instance = getattr(resource_instance, field.child_relation.source)
302281
except AttributeError:
303282
if not hasattr(current_serializer, field.source):
304283
continue
305284
serializer_method = getattr(current_serializer, field.source)
306-
relation_instance_or_manager = serializer_method(resource_instance)
285+
relation_instance = serializer_method(resource_instance)
286+
287+
if isinstance(relation_instance, Manager):
288+
relation_instance = relation_instance.all()
307289

308290
new_included_resources = [key.replace('%s.' % field_name, '', 1)
309291
for key in included_resources
310292
if field_name == key.split('.')[0]]
311293
serializer_data = resource.get(field_name)
312294

313295
if isinstance(field, relations.ManyRelatedField):
314-
serializer_class = included_serializers.get(field_name)
315-
field = serializer_class(relation_instance_or_manager.all(), many=True, context=context)
296+
serializer_class = included_serializers[field_name]
297+
field = serializer_class(relation_instance, many=True, context=context)
316298
serializer_data = field.data
317299

318300
if isinstance(field, relations.RelatedField):
319-
serializer_class = included_serializers.get(field_name)
320-
if relation_instance_or_manager is None:
301+
if relation_instance is None:
321302
continue
322-
field = serializer_class(relation_instance_or_manager, context=context)
303+
serializer_class = included_serializers[field_name]
304+
field = serializer_class(relation_instance, context=context)
323305
serializer_data = field.data
324306

325307
if isinstance(field, ListSerializer):
326308
serializer = field.child
327309
relation_type = utils.get_resource_type_from_serializer(serializer)
328-
relation_queryset = list(relation_instance_or_manager.all())
310+
relation_queryset = list(relation_instance)
329311

330312
# Get the serializer fields
331313
serializer_fields = utils.get_serializer_fields(serializer)
@@ -348,7 +330,7 @@ def extract_included(fields, resource, resource_instance, included_resources):
348330
)
349331
)
350332

351-
if isinstance(field, ModelSerializer):
333+
if isinstance(field, Serializer):
352334

353335
relation_type = utils.get_resource_type_from_serializer(field)
354336

@@ -358,11 +340,11 @@ def extract_included(fields, resource, resource_instance, included_resources):
358340
included_data.append(
359341
JSONRenderer.build_json_resource_obj(
360342
serializer_fields, serializer_data,
361-
relation_instance_or_manager, relation_type)
343+
relation_instance, relation_type)
362344
)
363345
included_data.extend(
364346
JSONRenderer.extract_included(
365-
serializer_fields, serializer_data, relation_instance_or_manager, new_included_resources
347+
serializer_fields, serializer_data, relation_instance, new_included_resources
366348
)
367349
)
368350

0 commit comments

Comments
 (0)