Repository: django-json-api/django-rest-framework-json-api

Issue:
ResourceRelatedField.source doesn't allow nested paths
Compared to how DRF allow nested paths in source:
https://github.com/encode/django-rest-framework/blob/master/rest_framework/fields.py#L401

DJA doesn't allow it:
https://github.com/django-json-api/django-rest-framework-json-api/blob/51daed1a738aadb1536a6a3cbe787cbd88daaf05/rest_framework_json_api/utils.py#L204

Examples here: https://www.django-rest-framework.org/api-guide/fields/#source
`EmailField(source='user.email')`


Discussion:
As far as I see does this only affect `ResourceRelatedField` for all other serializer fields dotted source should work.

I wonder why `relation.get_attribute(model)` is not used there which should solve this issue.

Resolving patch:
diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py
--- a/rest_framework_json_api/utils.py
+++ b/rest_framework_json_api/utils.py
@@ -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):


Test patch:
diff --git a/tests/models.py b/tests/models.py
--- a/tests/models.py
+++ b/tests/models.py
@@ -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
+    )
diff --git a/tests/test_utils.py b/tests/test_utils.py
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -25,6 +25,7 @@
     ForeignKeyTarget,
     ManyToManySource,
     ManyToManyTarget,
+    NestedRelatedSource,
 )
 from tests.serializers import BasicModelSerializer
 
@@ -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",
     [