77from django .utils import six , encoding
88from django .utils .translation import ugettext_lazy as _
99from 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
1112from rest_framework .settings import api_settings
1213from rest_framework .exceptions import APIException
1314
1415from django .utils .six .moves .urllib .parse import urlparse
1516
16-
1717try :
1818 from rest_framework .compat import OrderedDict
1919except ImportError :
@@ -153,10 +153,15 @@ def get_related_resource_type(relation):
153153 parent_model = parent_serializer .Meta .model
154154 else :
155155 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+
160165 if hasattr (parent_model_relation , 'related' ):
161166 relation_model = parent_model_relation .related .model
162167 elif hasattr (parent_model_relation , 'field' ):
@@ -193,11 +198,13 @@ def extract_relationships(fields, resource, resource_instance):
193198 if not isinstance (field , (RelatedField , ManyRelatedField , BaseSerializer )):
194199 continue
195200
196- if isinstance (field , HyperlinkedRouterField ):
197- # special case for HyperlinkedRouterField
201+ if isinstance (field , HyperlinkedIdentityField ):
202+ # special case for HyperlinkedIdentityField
198203 relation_data = list ()
199204 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 ()
201208 for relation in related :
202209 relation_data .append (OrderedDict ([('type' , relation_type ), ('id' , encoding .force_text (relation .pk ))]))
203210
@@ -213,38 +220,39 @@ def extract_relationships(fields, resource, resource_instance):
213220
214221 if isinstance (field , (PrimaryKeyRelatedField , HyperlinkedRelatedField )):
215222 relation_type = get_related_resource_type (field )
223+ relation_id = getattr (resource_instance , field_name ).pk if resource .get (field_name ) else None
216224
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 {}
230234 )
235+ data .update ({field_name : relation_data })
231236 continue
232237
233238 if isinstance (field , ManyRelatedField ):
234239 relation_data = list ()
235-
236240 relation = field .child_relation
237241 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
248256
249257 if isinstance (field , ListSerializer ):
250258 relation_data = list ()
@@ -284,7 +292,7 @@ def extract_relationships(fields, resource, resource_instance):
284292 return format_keys (data )
285293
286294
287- def extract_included (fields , resource ):
295+ def extract_included (fields , resource , resource_instance ):
288296 included_data = list ()
289297 for field_name , field in six .iteritems (fields ):
290298 # Skip URL field
@@ -305,8 +313,15 @@ def extract_included(fields, resource):
305313 serializer_fields = get_serializer_fields (serializer )
306314 serializer_data = resource .get (field_name )
307315 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+ )
310325
311326 if isinstance (field , ModelSerializer ):
312327
@@ -316,7 +331,10 @@ def extract_included(fields, resource):
316331 # Get the serializer fields
317332 serializer_fields = get_serializer_fields (field )
318333 serializer_data = resource .get (field_name )
334+ nested_resource_instance = getattr (resource_instance , field_name ).all ()
319335 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+ )
321339
322340 return format_keys (included_data )
0 commit comments