Skip to content

Commit 54bbf82

Browse files
committed
Merge pull request #69 from django-json-api/feature/drf-nested-routers
Introduced support for nested relationships urls with drf-nested-routers HyperlinkedRouterField
2 parents 403a4b2 + 0efc088 commit 54bbf82

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

rest_framework_json_api/renderers.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,20 @@ def render(self, data, accepted_media_type=None, renderer_context=None):
6969
fields = utils.get_serializer_fields(resource_serializer)
7070

7171
json_api_data = list()
72-
for resource in results:
72+
for position in range(len(results)):
73+
resource = results[position] # Get current resource
74+
resource_instance = resource_serializer.instance[position] # Get current instance
7375
json_api_data.append(
74-
utils.build_json_resource_obj(fields, resource, resource_name))
76+
utils.build_json_resource_obj(fields, resource, resource_instance, resource_name))
7577
included = utils.extract_included(fields, resource)
7678
if included:
7779
json_api_included.extend(included)
7880
else:
7981
# Check if data contains a serializer
8082
if hasattr(data, 'serializer'):
8183
fields = utils.get_serializer_fields(data.serializer)
82-
json_api_data = utils.build_json_resource_obj(fields, data, resource_name)
84+
resource_instance = data.serializer.instance
85+
json_api_data = utils.build_json_resource_obj(fields, data, resource_instance, resource_name)
8386
included = utils.extract_included(fields, data)
8487
if included:
8588
json_api_included.extend(included)

rest_framework_json_api/utils.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
from django.utils.six.moves.urllib.parse import urlparse
1515

16+
1617
try:
1718
from rest_framework.compat import OrderedDict
1819
except ImportError:
@@ -23,6 +24,11 @@
2324
except ImportError:
2425
ManyRelatedField = type(None)
2526

27+
try:
28+
from rest_framework_nested.relations import HyperlinkedRouterField
29+
except ImportError:
30+
HyperlinkedRouterField = type(None)
31+
2632

2733
def get_resource_name(context):
2834
"""
@@ -122,13 +128,13 @@ def format_value(value, format_type=None):
122128
return value
123129

124130

125-
def build_json_resource_obj(fields, resource, resource_name):
131+
def build_json_resource_obj(fields, resource, resource_instance, resource_name):
126132
resource_data = [
127133
('type', resource_name),
128134
('id', extract_id(fields, resource)),
129135
('attributes', extract_attributes(fields, resource)),
130136
]
131-
relationships = extract_relationships(fields, resource)
137+
relationships = extract_relationships(fields, resource, resource_instance)
132138
if relationships:
133139
resource_data.append(('relationships', relationships))
134140
# Add 'self' link if field is present and valid
@@ -139,9 +145,8 @@ def build_json_resource_obj(fields, resource, resource_name):
139145

140146

141147
def get_related_resource_type(relation):
142-
queryset = relation.queryset
143-
if queryset is not None:
144-
relation_model = queryset.model
148+
if hasattr(relation, 'get_queryset') and relation.get_queryset() is not None:
149+
relation_model = relation.get_queryset().model
145150
else:
146151
parent_serializer = relation.parent
147152
if hasattr(parent_serializer, 'Meta'):
@@ -198,7 +203,7 @@ def extract_attributes(fields, resource):
198203
return format_keys(data)
199204

200205

201-
def extract_relationships(fields, resource):
206+
def extract_relationships(fields, resource, resource_instance):
202207
data = OrderedDict()
203208
for field_name, field in six.iteritems(fields):
204209
# Skip URL field
@@ -209,6 +214,24 @@ def extract_relationships(fields, resource):
209214
if not isinstance(field, (RelatedField, ManyRelatedField, BaseSerializer)):
210215
continue
211216

217+
if isinstance(field, HyperlinkedRouterField):
218+
# special case for HyperlinkedRouterField
219+
relation_data = list()
220+
relation_type = get_related_resource_type(field)
221+
related = getattr(resource_instance, field_name).all()
222+
for relation in related:
223+
relation_data.append(OrderedDict([('type', relation_type), ('id', relation.pk)]))
224+
225+
data.update({field_name: {
226+
'links': {
227+
"related": resource.get(field_name)},
228+
'data': relation_data,
229+
'meta': {
230+
'count': len(relation_data)
231+
}
232+
}})
233+
continue
234+
212235
if isinstance(field, (PrimaryKeyRelatedField, HyperlinkedRelatedField)):
213236
relation_type = get_related_resource_type(field)
214237

0 commit comments

Comments
 (0)