Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2d0303b

Browse files
author
Oliver Sauder
committed
Added nested included serializer support for remapped relations
1 parent dec89af commit 2d0303b

File tree

5 files changed

+60
-16
lines changed

5 files changed

+60
-16
lines changed

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ v2.3.0
66
* Fix for apps that don't use `django.contrib.contenttypes`.
77
* Fix `resource_name` support for POST requests and nested serializers
88
* Enforcing flake8 linting
9+
* Added nested included serializer support for remapped relations
910

1011
v2.2.0
1112

‎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
@@ -82,14 +82,15 @@ def test_missing_field_not_included(author_bio_factory, author_factory, client):
8282

8383
def test_deep_included_data_on_list(multiple_entries, client):
8484
response = client.get(reverse("entry-list") + '?include=comments,comments.author,'
85-
'comments.author.bio&page_size=5')
85+
'comments.author.bio,comments.writer&page_size=5')
8686
included = load_json(response.content).get('included')
8787

8888
assert len(load_json(response.content)['data']) == len(multiple_entries), (
8989
'Incorrect entry count'
9090
)
9191
assert [x.get('type') for x in included] == [
92-
'authorBios', 'authorBios', 'authors', 'authors', 'comments', 'comments'
92+
'authorBios', 'authorBios', 'authors', 'authors',
93+
'comments', 'comments', 'writers', 'writers'
9394
], 'List included types are incorrect'
9495

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

110+
writer_count = len(
111+
[resource for resource in included if resource["type"] == "writers"]
112+
)
113+
expected_writer_count = sum(
114+
[entry.comments.filter(author__isnull=False).count() for entry in multiple_entries])
115+
assert writer_count == expected_writer_count, 'List writer count is incorrect'
116+
109117
# Also include entry authors
110118
response = client.get(reverse("entry-list") + '?include=authors,comments,comments.author,'
111119
'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
@@ -102,6 +102,12 @@ def test_model_serializer_with_implicit_fields(self, comment, client):
102102
"id": str(comment.author.pk)
103103
}
104104
},
105+
"writer": {
106+
"data": {
107+
"type": "writers",
108+
"id": str(comment.author.pk)
109+
}
110+
},
105111
}
106112
}
107113
}

‎rest_framework_json_api/renderers.py‎

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

273273
return utils.format_keys(data)
274274

275+
@classmethod
276+
def extract_relation_instance(cls, field_name, field, resource_instance, serializer):
277+
relation_instance = None
278+
279+
try:
280+
relation_instance = getattr(resource_instance, field_name)
281+
except AttributeError:
282+
try:
283+
# For ManyRelatedFields if `related_name` is not set
284+
# we need to access `foo_set` from `source`
285+
relation_instance = getattr(resource_instance, field.child_relation.source)
286+
except AttributeError:
287+
if hasattr(serializer, field.source):
288+
serializer_method = getattr(serializer, field.source)
289+
relation_instance = serializer_method(resource_instance)
290+
else:
291+
# case when source is a simple remap on resource_instance
292+
try:
293+
relation_instance = getattr(resource_instance, field.source)
294+
except AttributeError:
295+
pass
296+
297+
return relation_instance
298+
275299
@classmethod
276300
def extract_included(cls, fields, resource, resource_instance, included_resources):
277301
# this function may be called with an empty record (example: Browsable Interface)
@@ -304,19 +328,9 @@ def extract_included(cls, fields, resource, resource_instance, included_resource
304328
if field_name not in [node.split('.')[0] for node in included_resources]:
305329
continue
306330

307-
try:
308-
relation_instance = getattr(resource_instance, field_name)
309-
except AttributeError:
310-
try:
311-
# For ManyRelatedFields if `related_name` is not set we need to access `foo_set`
312-
# from `source`
313-
relation_instance = getattr(resource_instance, field.child_relation.source)
314-
except AttributeError:
315-
if not hasattr(current_serializer, field.source):
316-
continue
317-
serializer_method = getattr(current_serializer, field.source)
318-
relation_instance = serializer_method(resource_instance)
319-
331+
relation_instance = cls.extract_relation_instance(
332+
field_name, field, resource_instance, current_serializer
333+
)
320334
if isinstance(relation_instance, Manager):
321335
relation_instance = relation_instance.all()
322336

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /