Skip to content

Commit

Permalink
Support many related field (#1065)
Browse files Browse the repository at this point in the history
Co-authored-by: Oliver Sauder <os@esite.ch>
  • Loading branch information
bashlyss and sliverc authored Jul 13, 2022
1 parent f9eb277 commit bbeb13a
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 9 deletions.
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

0 comments on commit bbeb13a

Please sign in to comment.