Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Adam Wróbel <https://adamwrobel.com>
Adam Ziolkowski <adam@adsized.com>
Alan Crosswell <alan@columbia.edu>
Anton Shutik <shutikanton@gmail.com>
Ashley Loewen <github@ashleycodes.tech>
Asif Saif Uddin <auvipy@gmail.com>
Beni Keller <beni@matraxi.ch>
Boris Pleshakov <koordinator.kun@gmail.com>
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ any parts of the framework not mentioned in the documentation should generally b
### Fixed

* Fixed invalid relationship pointer in error objects when field naming formatting is used.
* Properly resolved related resource type when nested source field is defined.

## [5.0.0] - 2022-01-03

Expand Down
18 changes: 9 additions & 9 deletions rest_framework_json_api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,15 @@ def get_related_resource_type(relation):
relation_model = relation.model
elif hasattr(relation, "get_queryset") and relation.get_queryset() is not None:
relation_model = relation.get_queryset().model
elif (
getattr(relation, "many", False)
and hasattr(relation.child, "Meta")
and hasattr(relation.child.Meta, "model")
):
# For ManyToMany relationships, get the model from the child
# serializer of the list serializer
relation_model = relation.child.Meta.model
else:
elif hasattr(relation, "child_relation"):
# For ManyRelatedField relationships, get the model from the child relationship
try:
return get_related_resource_type(relation.child_relation)
except AttributeError:
# Some read only relationships fail to get it directly, fall through to
# get via the parent
pass
if not relation_model:
parent_serializer = relation.parent
parent_model = None
if isinstance(parent_serializer, PolymorphicModelSerializer):
Expand Down
11 changes: 11 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,14 @@ class ForeignKeySource(DJAModel):
target = models.ForeignKey(
ForeignKeyTarget, related_name="sources", on_delete=models.CASCADE
)


class NestedRelatedSource(DJAModel):
m2m_source = models.ManyToManyField(ManyToManySource, related_name="nested_source")
fk_source = models.ForeignKey(
ForeignKeySource, related_name="nested_source", on_delete=models.CASCADE
)
m2m_target = models.ManyToManyField(ManyToManySource, related_name="nested_source")
fk_target = models.ForeignKey(
ForeignKeySource, related_name="nested_source", on_delete=models.CASCADE
)
43 changes: 43 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
ForeignKeyTarget,
ManyToManySource,
ManyToManyTarget,
NestedRelatedSource,
)
from tests.serializers import BasicModelSerializer

Expand Down Expand Up @@ -313,6 +314,48 @@ class Meta:
assert get_related_resource_type(field) == output


@pytest.mark.parametrize(
"field,output,related_field_kwargs",
[
(
"m2m_source.targets",
"ManyToManyTarget",
{"many": True, "queryset": ManyToManyTarget.objects.all()},
),
(
"m2m_target.sources.",
"ManyToManySource",
{"many": True, "queryset": ManyToManySource.objects.all()},
),
(
"fk_source.target",
"ForeignKeyTarget",
{"many": True, "queryset": ForeignKeyTarget.objects.all()},
),
(
"fk_target.source",
"ForeignKeySource",
{"many": True, "queryset": ForeignKeySource.objects.all()},
),
],
)
def test_get_related_resource_type_from_nested_source(
db, field, output, related_field_kwargs
):
class RelatedResourceTypeSerializer(serializers.ModelSerializer):
relation = serializers.ResourceRelatedField(
source=field, **related_field_kwargs
)

class Meta:
model = NestedRelatedSource
fields = ("relation",)

serializer = RelatedResourceTypeSerializer()
field = serializer.fields["relation"]
assert get_related_resource_type(field) == output


@pytest.mark.parametrize(
"related_field_kwargs,output",
[
Expand Down