graphql-python / graphql-python/graphene-django
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`
- Dominant language
- Python
- Stars
- 4.4k
- Forks
- 760
- PR merge metrics
- No merged PRs in 30d
Description
## **What is the current behavior?**
Given the following models:
```python
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:
```python
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:
```python
import graphene
from graphene_django.fields import DjangoConnectionField
class Query(graphene.ObjectType):
examples = DjangoConnectionField(ExampleType)
related = DjangoConnectionField(RelatedType)
```
Now, trying to query like this:
```graphql
query {
examples {
edges {
node {
id
related {
id
}
}
}
}
}
```
... will result in an error like this:
```json
[
{
"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:
1. The `Related` model field `example` is a `OneToOneField`, which has defined a `related_query_name` different from the field's `related_name`.
2. 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](https://github.com/graphql-python/graphene-django/blob/62126dd46753ecce4f2b95bf63c1a7d08b1a91a2/graphene_django/converter.py#L283)
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](https://github.com/django/django/blob/b287af5dc954628d4b336aefc5027b2edceee64b/django/db/models/options.py#L649)). 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_name`s instead of `related_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 defined `get_queryset`. This reduces boilerplate code, since otherwise I would need to define the field and resolver manually.
---
## **Please tell us about your environment:**
- Version: v3.1.5
- Platform: Windows 11
---
Contributor guide
Assessment
This issue has not been assessed yet.