Automatic object type field for reverse one-to-one model fields cannot resolve when model field has `related_query_name` and object type has custom `get_queryset` #1484
from django.db import models
class Example(models.Model):
pass
class Related(models.Model):
example = models.OneToOneField(
Example,
on_delete=models.CASCADE,
related_name="related",
# Important!
related_query_name="related_item",
)
... and the following ObjectTypes:
import graphene
from graphene_django import DjangoObjectType
from graphene_django.fields import DjangoConnectionField
class ExampleType(DjangoObjectType):
class Meta:
model = Example
fields = [
"id",
"related",
]
connection_class = graphene.Connection
interfaces = (graphene.relay.Node,)
class RelatedType(DjangoObjectType):
class Meta:
model = Related
fields = [
"id",
"example",
]
connection_class = graphene.Connection
interfaces = (graphene.relay.Node,)
# Important!
@classmethod
def get_queryset(cls, queryset, info):
return queryset
... and the following query definitions:
import graphene
from graphene_django.fields import DjangoConnectionField
class Query(graphene.ObjectType):
examples = DjangoConnectionField(ExampleType)
related = DjangoConnectionField(RelatedType)
Now, trying to query like this:
query {
examples {
edges {
node {
id
related {
id
}
}
}
}
}
... will result in an error like this:
[
{
"locations": [
{
"column": 9,
"line": 3,
},
],
"message": "Example has no field named 'related'",
"path": [
"examples",
"edges",
0,
"node",
"related",
],
}
]
What causes the current behavior?
This happens because of two things:
The Related model field example is a OneToOneField, which has defined a related_query_name different from the field's related_name.
The RelatedType ObjectType defined the get_queryset class method.
When graphene_django.converter.convert_onetoone_field_to_djangomodel creates a the ObjectType for the ExampleType field related, it uses the RelatedType ObjectType's queryset for this check: graphene_django.converter.py:283
Since the RelatedType's get_queryset was modified, this check does not early return, thus we use the custom_resolver below that.
When custom_resolver resolves, it tries to fetch reversed_field_name from the class fields (uses django.db.models.options.py:649). Since related is a reverse relation, it does not exist in _forward_fields_map. However, _it's not found from fields_map either_, since the keys in fields_map use fields' related_query_names instead of related_names.
Therefore, automatic field object type creation fails in this case (reverse one-to-one fields with get_queryset defined).
What is the expected behavior?
I should be able to make the query described above with the given object type configuration.
What is the motivation / use case for changing the behavior?
I should be able to rely on automatic field generaton for reverse one-to-one relations with related_query_name to object types that have defined get_queryset. This reduces boilerplate code, since otherwise I would need to define the field and resolver manually.
What is the current behavior?
Given the following models:
... and the following ObjectTypes:
... and the following query definitions:
Now, trying to query like this:
... will result in an error like this:
What causes the current behavior?
This happens because of two things:
The
Related
model fieldexample
is aOneToOneField
, which has defined arelated_query_name
different from the field'srelated_name
.The
RelatedType
ObjectType defined theget_queryset
class method.When
graphene_django.converter.convert_onetoone_field_to_djangomodel
creates a the ObjectType for the ExampleType fieldrelated
, it uses theRelatedType
ObjectType's queryset for this check: graphene_django.converter.py:283Since the
RelatedType
'sget_queryset
was modified, this check does not early return, thus we use thecustom_resolver
below that.When
custom_resolver
resolves, it tries to fetchreversed_field_name
from the class fields (uses django.db.models.options.py:649). Sincerelated
is a reverse relation, it does not exist in_forward_fields_map
. However, _it's not found fromfields_map
either_, since the keys infields_map
use fields'related_query_name
s instead ofrelated_name
s.Therefore, automatic field object type creation fails in this case (reverse one-to-one fields with
get_queryset
defined).What is the expected behavior?
I should be able to make the query described above with the given object type configuration.
What is the motivation / use case for changing the behavior?
I should be able to rely on automatic field generaton for reverse one-to-one relations with
related_query_name
to object types that have definedget_queryset
. This reduces boilerplate code, since otherwise I would need to define the field and resolver manually.Please tell us about your environment: