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 5488b18

Browse files
authored
Render meta_fields in included resources (#883)
For consistency reasons the meta fields should also be rendered in included resources.
1 parent 952e26b commit 5488b18

File tree

8 files changed

+60
-25
lines changed

8 files changed

+60
-25
lines changed

‎AUTHORS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Matt Layman <https://www.mattlayman.com>
2323
Michael Haselton <icereval@gmail.com>
2424
Mohammed Ali Zubair <mazg1493@gmail.com>
2525
Nathanael Gordon <nathanael.l.gordon@gmail.com>
26+
Nick Kozhenin <kozhenin.nick@gmail.com>
2627
Ola Tarkowska <ola@red-aries.com>
2728
Oliver Sauder <os@esite.ch>
2829
Raphael Cohen <raphael.cohen.utt@gmail.com>

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ any parts of the framework not mentioned in the documentation should generally b
1919

2020
* Allow users to overwrite a view's `get_serializer_class()` method when using [related urls](https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html#related-urls)
2121
* Correctly resolve the resource type of `ResourceRelatedField(many=True)` fields on plain serializers
22+
* Render `meta_fields` in included resources
2223

2324

2425
## [4.0.0] - 2020年10月31日

‎example/serializers.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ class AuthorSerializer(serializers.ModelSerializer):
251251
write_only=True,
252252
help_text="help for defaults",
253253
)
254+
initials = serializers.SerializerMethodField()
254255
included_serializers = {"bio": AuthorBioSerializer, "type": AuthorTypeSerializer}
255256
related_serializers = {
256257
"bio": "example.serializers.AuthorBioSerializer",
@@ -272,11 +273,16 @@ class Meta:
272273
"type",
273274
"secrets",
274275
"defaults",
276+
"initials",
275277
)
278+
meta_fields = ("initials",)
276279

277280
def get_first_entry(self, obj):
278281
return obj.entries.first()
279282

283+
def get_initials(self, obj):
284+
return "".join([word[0] for word in obj.name.split(" ")])
285+
280286

281287
class AuthorListSerializer(AuthorSerializer):
282288
pass
@@ -298,6 +304,7 @@ class Meta:
298304
class CommentSerializer(serializers.ModelSerializer):
299305
# testing remapping of related name
300306
writer = relations.ResourceRelatedField(source="author", read_only=True)
307+
modified_days_ago = serializers.SerializerMethodField()
301308

302309
included_serializers = {
303310
"entry": EntrySerializer,
@@ -312,6 +319,10 @@ class Meta:
312319
"modified_at",
313320
)
314321
# fields = ('entry', 'body', 'author',)
322+
meta_fields = ("modified_days_ago",)
323+
324+
def get_modified_days_ago(self, obj):
325+
return (datetime.now() - obj.modified_at).days
315326

316327

317328
class ProjectTypeSerializer(serializers.ModelSerializer):

‎example/tests/integration/test_includes.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,17 @@ def test_data_resource_not_included_again(single_comment, client):
261261
# The comment in the data attribute must not be included again.
262262
expected_comment_count -= 1
263263
assert comment_count == expected_comment_count, "Comment count incorrect"
264+
265+
266+
def test_meta_object_added_to_included_resources(single_entry, client):
267+
response = client.get(
268+
reverse("entry-detail", kwargs={"pk": single_entry.pk}) + "?include=comments"
269+
)
270+
assert response.json()["included"][0].get("meta")
271+
272+
response = client.get(
273+
reverse("entry-detail", kwargs={"pk": single_entry.pk})
274+
+ "?include=comments.author"
275+
)
276+
assert response.json()["included"][0].get("meta")
277+
assert response.json()["included"][1].get("meta")

‎example/tests/test_format_keys.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,6 @@ def test_options_format_field_names(db, client):
6363
"comments",
6464
"secrets",
6565
"defaults",
66+
"initials",
6667
}
6768
assert expected_keys == data["actions"]["POST"].keys()

‎example/tests/test_serializers.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ def test_model_serializer_with_implicit_fields(self, comment, client):
195195
"data": {"type": "writers", "id": str(comment.author.pk)}
196196
},
197197
},
198+
"meta": {
199+
"modifiedDaysAgo": (datetime.now() - comment.modified_at).days
200+
},
198201
}
199202
}
200203

‎example/tests/unit/test_renderer_class_methods.py‎

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from rest_framework_json_api import serializers
55
from rest_framework_json_api.renderers import JSONRenderer
6+
from rest_framework_json_api.utils import get_serializer_fields
67

78
pytestmark = pytest.mark.django_db
89

@@ -20,10 +21,7 @@ class Meta:
2021

2122

2223
def test_build_json_resource_obj():
23-
resource = {
24-
"pk": 1,
25-
"username": "Alice",
26-
}
24+
resource = {"username": "Alice", "version": "1.0.0"}
2725

2826
serializer = ResourceSerializer(data={"username": "Alice"})
2927
serializer.is_valid()
@@ -33,11 +31,16 @@ def test_build_json_resource_obj():
3331
"type": "user",
3432
"id": "1",
3533
"attributes": {"username": "Alice"},
34+
"meta": {"version": "1.0.0"},
3635
}
3736

3837
assert (
3938
JSONRenderer.build_json_resource_obj(
40-
serializer.fields, resource, resource_instance, "user"
39+
get_serializer_fields(serializer),
40+
resource,
41+
resource_instance,
42+
"user",
43+
serializer,
4144
)
4245
== output
4346
)
@@ -47,11 +50,8 @@ def test_can_override_methods():
4750
"""
4851
Make sure extract_attributes and extract_relationships can be overriden.
4952
"""
50-
resource = {
51-
"pk": 1,
52-
"username": "Alice",
53-
}
5453

54+
resource = {"username": "Alice", "version": "1.0.0"}
5555
serializer = ResourceSerializer(data={"username": "Alice"})
5656
serializer.is_valid()
5757
resource_instance = serializer.save()
@@ -60,6 +60,7 @@ def test_can_override_methods():
6060
"type": "user",
6161
"id": "1",
6262
"attributes": {"username": "Alice"},
63+
"meta": {"version": "1.0.0"},
6364
}
6465

6566
class CustomRenderer(JSONRenderer):
@@ -80,7 +81,11 @@ def extract_relationships(cls, fields, resource, resource_instance):
8081

8182
assert (
8283
CustomRenderer.build_json_resource_obj(
83-
serializer.fields, resource, resource_instance, "user"
84+
get_serializer_fields(serializer),
85+
resource,
86+
resource_instance,
87+
"user",
88+
serializer,
8489
)
8590
== output
8691
)

‎rest_framework_json_api/renderers.py‎

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -373,11 +373,11 @@ def extract_included(
373373
serializer_resource,
374374
nested_resource_instance,
375375
resource_type,
376+
serializer,
376377
getattr(serializer, "_poly_force_type_resolution", False),
377378
)
378-
included_cache[new_item["type"]][
379-
new_item["id"]
380-
] = utils.format_field_names(new_item)
379+
included_cache[new_item["type"]][new_item["id"]] = new_item
380+
381381
cls.extract_included(
382382
serializer_fields,
383383
serializer_resource,
@@ -397,11 +397,11 @@ def extract_included(
397397
serializer_data,
398398
relation_instance,
399399
relation_type,
400+
field,
400401
getattr(field, "_poly_force_type_resolution", False),
401402
)
402-
included_cache[new_item["type"]][
403-
new_item["id"]
404-
] = utils.format_field_names(new_item)
403+
included_cache[new_item["type"]][new_item["id"]] = new_item
404+
405405
cls.extract_included(
406406
serializer_fields,
407407
serializer_data,
@@ -450,6 +450,7 @@ def build_json_resource_obj(
450450
resource,
451451
resource_instance,
452452
resource_name,
453+
serializer,
453454
force_type_resolution=False,
454455
):
455456
"""
@@ -476,6 +477,11 @@ def build_json_resource_obj(
476477
resource_data.append(
477478
("links", {"self": resource[api_settings.URL_FIELD_NAME]})
478479
)
480+
481+
meta = cls.extract_meta(serializer, resource)
482+
if meta:
483+
resource_data.append(("meta", utils.format_field_names(meta)))
484+
479485
return OrderedDict(resource_data)
480486

481487
def render_relationship_view(
@@ -582,13 +588,9 @@ def render(self, data, accepted_media_type=None, renderer_context=None):
582588
resource,
583589
resource_instance,
584590
resource_name,
591+
serializer,
585592
force_type_resolution,
586593
)
587-
meta = self.extract_meta(serializer, resource)
588-
if meta:
589-
json_resource_obj.update(
590-
{"meta": utils.format_field_names(meta)}
591-
)
592594
json_api_data.append(json_resource_obj)
593595

594596
self.extract_included(
@@ -610,13 +612,10 @@ def render(self, data, accepted_media_type=None, renderer_context=None):
610612
serializer_data,
611613
resource_instance,
612614
resource_name,
615+
serializer,
613616
force_type_resolution,
614617
)
615618

616-
meta = self.extract_meta(serializer, serializer_data)
617-
if meta:
618-
json_api_data.update({"meta": utils.format_field_names(meta)})
619-
620619
self.extract_included(
621620
fields,
622621
serializer_data,

0 commit comments

Comments
(0)

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