55from collections import OrderedDict
66
77import inflection
8+ from django .db .models import Manager , QuerySet
89from django .utils import six , encoding
910from rest_framework import relations
1011from rest_framework import renderers
11- from rest_framework .serializers import BaseSerializer , ListSerializer , ModelSerializer
12+ from rest_framework .serializers import BaseSerializer , Serializer , ListSerializer
1213from rest_framework .settings import api_settings
1314
1415from . 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