Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 03f7943

Browse files
author
Oliver Sauder
committed
Added nested included serializer support for remapped relations
1 parent 76b60fe commit 03f7943

File tree

4 files changed

+59
-15
lines changed

4 files changed

+59
-15
lines changed

example/serializers.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,25 @@ class Meta:
105105
fields = ('name', 'email', 'bio')
106106

107107

108+
class WriterSerializer(serializers.ModelSerializer):
109+
included_serializers = {
110+
'bio': AuthorBioSerializer
111+
}
112+
113+
class Meta:
114+
model = Author
115+
fields = ('name', 'email', 'bio')
116+
resource_name = 'writers'
117+
118+
108119
class CommentSerializer(serializers.ModelSerializer):
120+
# testing remapping of related name
121+
writer = relations.ResourceRelatedField(source='author', read_only=True)
122+
109123
included_serializers = {
110124
'entry': EntrySerializer,
111-
'author': AuthorSerializer
125+
'author': AuthorSerializer,
126+
'writer': WriterSerializer
112127
}
113128

114129
class Meta:

example/tests/integration/test_includes.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,13 @@ def test_missing_field_not_included(author_bio_factory, author_factory, client):
7272

7373
def test_deep_included_data_on_list(multiple_entries, client):
7474
response = client.get(reverse("entry-list") + '?include=comments,comments.author,'
75-
'comments.author.bio&page_size=5')
75+
'comments.author.bio,comments.writer&page_size=5')
7676
included = load_json(response.content).get('included')
7777

7878
assert len(load_json(response.content)['data']) == len(multiple_entries), 'Incorrect entry count'
7979
assert [x.get('type') for x in included] == [
80-
'authorBios', 'authorBios', 'authors', 'authors', 'comments', 'comments'
80+
'authorBios', 'authorBios', 'authors', 'authors',
81+
'comments', 'comments', 'writers', 'writers'
8182
], 'List included types are incorrect'
8283

8384
comment_count = len([resource for resource in included if resource["type"] == "comments"])
@@ -94,6 +95,13 @@ def test_deep_included_data_on_list(multiple_entries, client):
9495
author__bio__isnull=False).count() for entry in multiple_entries])
9596
assert author_bio_count == expected_author_bio_count, 'List author bio count is incorrect'
9697

98+
writer_count = len(
99+
[resource for resource in included if resource["type"] == "writers"]
100+
)
101+
expected_writer_count = sum(
102+
[entry.comments.filter(author__isnull=False).count() for entry in multiple_entries])
103+
assert writer_count == expected_writer_count, 'List writer count is incorrect'
104+
97105
# Also include entry authors
98106
response = client.get(reverse("entry-list") + '?include=authors,comments,comments.author,'
99107
'comments.author.bio&page_size=5')

example/tests/test_serializers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ def test_model_serializer_with_implicit_fields(self, comment, client):
100100
"id": str(comment.author.pk)
101101
}
102102
},
103+
"writer": {
104+
"data": {
105+
"type": "writers",
106+
"id": str(comment.author.pk)
107+
}
108+
},
103109
}
104110
}
105111
}

rest_framework_json_api/renderers.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,30 @@ def extract_relationships(cls, fields, resource, resource_instance):
242242

243243
return utils.format_keys(data)
244244

245+
@classmethod
246+
def extract_relation_instance(cls, field_name, field, resource_instance, serializer):
247+
relation_instance = None
248+
249+
try:
250+
relation_instance = getattr(resource_instance, field_name)
251+
except AttributeError:
252+
try:
253+
# For ManyRelatedFields if `related_name` is not set
254+
# we need to access `foo_set` from `source`
255+
relation_instance = getattr(resource_instance, field.child_relation.source)
256+
except AttributeError:
257+
if hasattr(serializer, field.source):
258+
serializer_method = getattr(serializer, field.source)
259+
relation_instance = serializer_method(resource_instance)
260+
else:
261+
# case when source is a simple remap on resource_instance
262+
try:
263+
relation_instance = getattr(resource_instance, field.source)
264+
except AttributeError:
265+
pass
266+
267+
return relation_instance
268+
245269
@classmethod
246270
def extract_included(cls, fields, resource, resource_instance, included_resources):
247271
# this function may be called with an empty record (example: Browsable Interface)
@@ -272,18 +296,9 @@ def extract_included(cls, fields, resource, resource_instance, included_resource
272296
if field_name not in [node.split('.')[0] for node in included_resources]:
273297
continue
274298

275-
try:
276-
relation_instance = getattr(resource_instance, field_name)
277-
except AttributeError:
278-
try:
279-
# For ManyRelatedFields if `related_name` is not set we need to access `foo_set` from `source`
280-
relation_instance = getattr(resource_instance, field.child_relation.source)
281-
except AttributeError:
282-
if not hasattr(current_serializer, field.source):
283-
continue
284-
serializer_method = getattr(current_serializer, field.source)
285-
relation_instance = serializer_method(resource_instance)
286-
299+
relation_instance = cls.extract_relation_instance(
300+
field_name, field, resource_instance, current_serializer
301+
)
287302
if isinstance(relation_instance, Manager):
288303
relation_instance = relation_instance.all()
289304

0 commit comments

Comments
 (0)