7
7
from django .utils import six , encoding
8
8
from django .utils .translation import ugettext_lazy as _
9
9
from rest_framework .serializers import BaseSerializer , ListSerializer , ModelSerializer
10
- from rest_framework .relations import RelatedField , HyperlinkedRelatedField , PrimaryKeyRelatedField
10
+ from rest_framework .relations import RelatedField , HyperlinkedRelatedField , PrimaryKeyRelatedField , \
11
+ HyperlinkedIdentityField
11
12
from rest_framework .settings import api_settings
12
13
from rest_framework .exceptions import APIException
13
14
14
15
from django .utils .six .moves .urllib .parse import urlparse
15
16
16
-
17
17
try :
18
18
from rest_framework .compat import OrderedDict
19
19
except ImportError :
@@ -153,10 +153,15 @@ def get_related_resource_type(relation):
153
153
parent_model = parent_serializer .Meta .model
154
154
else :
155
155
parent_model = parent_serializer .parent .Meta .model
156
- parent_model_relation = getattr (
157
- parent_model ,
158
- (relation .source if relation .source else parent_serializer .field_name )
159
- )
156
+
157
+ if relation .source :
158
+ if relation .source != '*' :
159
+ parent_model_relation = getattr (parent_model , relation .source )
160
+ else :
161
+ parent_model_relation = getattr (parent_model , relation .field_name )
162
+ else :
163
+ parent_model_relation = getattr (parent_model , parent_serializer .field_name )
164
+
160
165
if hasattr (parent_model_relation , 'related' ):
161
166
relation_model = parent_model_relation .related .model
162
167
elif hasattr (parent_model_relation , 'field' ):
@@ -193,11 +198,13 @@ def extract_relationships(fields, resource, resource_instance):
193
198
if not isinstance (field , (RelatedField , ManyRelatedField , BaseSerializer )):
194
199
continue
195
200
196
- if isinstance (field , HyperlinkedRouterField ):
197
- # special case for HyperlinkedRouterField
201
+ if isinstance (field , HyperlinkedIdentityField ):
202
+ # special case for HyperlinkedIdentityField
198
203
relation_data = list ()
199
204
relation_type = get_related_resource_type (field )
200
- related = getattr (resource_instance , field_name ).all ()
205
+ relation_manager = getattr (resource_instance , field_name )
206
+ # Don't try to query an empty relation
207
+ related = relation_manager .all () if relation_manager is not None else list ()
201
208
for relation in related :
202
209
relation_data .append (OrderedDict ([('type' , relation_type ), ('id' , encoding .force_text (relation .pk ))]))
203
210
@@ -213,38 +220,39 @@ def extract_relationships(fields, resource, resource_instance):
213
220
214
221
if isinstance (field , (PrimaryKeyRelatedField , HyperlinkedRelatedField )):
215
222
relation_type = get_related_resource_type (field )
223
+ relation_id = getattr (resource_instance , field_name ).pk if resource .get (field_name ) else None
216
224
217
- if resource .get (field_name ) is not None :
218
- relation_id = getattr (resource_instance , field_name ).id
219
- else :
220
- relation_id = None
221
-
222
- data .update (
223
- {
224
- field_name : {
225
- 'data' : (OrderedDict ([
226
- ('type' , relation_type ), ('id' , encoding .force_text (relation_id ))
227
- ]) if relation_id is not None else None )
228
- }
229
- }
225
+ relation_data = {
226
+ 'data' : (OrderedDict ([
227
+ ('type' , relation_type ), ('id' , encoding .force_text (relation_id ))
228
+ ]) if relation_id is not None else None )
229
+ }
230
+
231
+ relation_data .update (
232
+ {'links' : {'related' : resource .get (field_name )}}
233
+ if isinstance (field , HyperlinkedRelatedField ) and resource .get (field_name ) else {}
230
234
)
235
+ data .update ({field_name : relation_data })
231
236
continue
232
237
233
238
if isinstance (field , ManyRelatedField ):
234
239
relation_data = list ()
235
-
236
240
relation = field .child_relation
237
241
relation_type = get_related_resource_type (relation )
238
- nested_resource_queryset = getattr (resource_instance , field_name ).all ()
239
- if isinstance (relation , (HyperlinkedRelatedField , PrimaryKeyRelatedField )):
240
- for position in range (len (nested_resource_queryset )):
241
- nested_resource_instance = nested_resource_queryset [position ]
242
- relation_data .append (
243
- OrderedDict ([('type' , relation_type ), ('id' , encoding .force_text (nested_resource_instance .pk ))])
244
- )
245
-
246
- data .update ({field_name : {'data' : relation_data }})
247
- continue
242
+ for related_object in getattr (resource_instance , field_name ).all ():
243
+ relation_data .append (OrderedDict ([
244
+ ('type' , relation_type ),
245
+ ('id' , encoding .force_text (related_object .pk ))
246
+ ]))
247
+ data .update ({
248
+ field_name : {
249
+ 'data' : relation_data ,
250
+ 'meta' : {
251
+ 'count' : len (relation_data )
252
+ }
253
+ }
254
+ })
255
+ continue
248
256
249
257
if isinstance (field , ListSerializer ):
250
258
relation_data = list ()
@@ -284,7 +292,7 @@ def extract_relationships(fields, resource, resource_instance):
284
292
return format_keys (data )
285
293
286
294
287
- def extract_included (fields , resource ):
295
+ def extract_included (fields , resource , resource_instance ):
288
296
included_data = list ()
289
297
for field_name , field in six .iteritems (fields ):
290
298
# Skip URL field
@@ -305,8 +313,15 @@ def extract_included(fields, resource):
305
313
serializer_fields = get_serializer_fields (serializer )
306
314
serializer_data = resource .get (field_name )
307
315
if isinstance (serializer_data , list ):
308
- for serializer_resource in serializer_data :
309
- included_data .append (build_json_resource_obj (serializer_fields , serializer_resource , relation_type ))
316
+ for position in range (len (serializer_data )):
317
+ serializer_resource = serializer_data [position ]
318
+ resource_instance_manager = getattr (resource_instance , field_name ).all ()
319
+ nested_resource_instance = resource_instance_manager [position ]
320
+ included_data .append (
321
+ build_json_resource_obj (
322
+ serializer_fields , serializer_resource , nested_resource_instance , relation_type
323
+ )
324
+ )
310
325
311
326
if isinstance (field , ModelSerializer ):
312
327
@@ -316,7 +331,10 @@ def extract_included(fields, resource):
316
331
# Get the serializer fields
317
332
serializer_fields = get_serializer_fields (field )
318
333
serializer_data = resource .get (field_name )
334
+ nested_resource_instance = getattr (resource_instance , field_name ).all ()
319
335
if serializer_data :
320
- included_data .append (build_json_resource_obj (serializer_fields , serializer_data , relation_type ))
336
+ included_data .append (
337
+ build_json_resource_obj (serializer_fields , serializer_data , nested_resource_instance , relation_type )
338
+ )
321
339
322
340
return format_keys (included_data )
0 commit comments