From 412705cb00a877a119800b39f97dce553f976c9e Mon Sep 17 00:00:00 2001 From: Laurent Date: Wed, 9 Aug 2023 17:28:26 +0000 Subject: [PATCH] fix: foreign key nullable and custom resolver (#1446) * fix: nullable one to one relation * fix: makefile --- Makefile | 2 +- graphene_django/converter.py | 15 +++--- graphene_django/tests/models.py | 6 ++- graphene_django/tests/test_query.py | 71 +++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 29c412bcc..ba005627a 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ dev-setup: .PHONY: tests ## Run unit tests tests: - py.test graphene_django --cov=graphene_django -vv + PYTHONPATH=. py.test graphene_django --cov=graphene_django -vv .PHONY: format ## Format code format: diff --git a/graphene_django/converter.py b/graphene_django/converter.py index 0c3a24eb5..4584306a4 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -302,12 +302,15 @@ def custom_resolver(root, info, **args): reversed_field_name = root.__class__._meta.get_field( field_name ).remote_field.name - return _type.get_queryset( - _type._meta.model.objects.filter( - **{reversed_field_name: root.pk} - ), - info, - ).get() + try: + return _type.get_queryset( + _type._meta.model.objects.filter( + **{reversed_field_name: root.pk} + ), + info, + ).get() + except _type._meta.model.DoesNotExist: + return None return custom_resolver diff --git a/graphene_django/tests/models.py b/graphene_django/tests/models.py index e7298383f..4afbbbce7 100644 --- a/graphene_django/tests/models.py +++ b/graphene_django/tests/models.py @@ -19,7 +19,11 @@ class Pet(models.Model): class FilmDetails(models.Model): location = models.CharField(max_length=30) film = models.OneToOneField( - "Film", on_delete=models.CASCADE, related_name="details" + "Film", + on_delete=models.CASCADE, + related_name="details", + null=True, + blank=True, ) diff --git a/graphene_django/tests/test_query.py b/graphene_django/tests/test_query.py index 3e01be49f..f60f5ee89 100644 --- a/graphene_django/tests/test_query.py +++ b/graphene_django/tests/test_query.py @@ -2065,3 +2065,74 @@ def resolve_person(self, info, name): assert result.data["person"] == { "pets": [{"name": "Jane's dog"}], } + + +def test_should_query_nullable_one_to_one_relation_with_custom_resolver(): + class FilmType(DjangoObjectType): + class Meta: + model = Film + + @classmethod + def get_queryset(cls, queryset, info): + return queryset + + class FilmDetailsType(DjangoObjectType): + class Meta: + model = FilmDetails + + @classmethod + def get_queryset(cls, queryset, info): + return queryset + + class Query(graphene.ObjectType): + film = graphene.Field(FilmType, genre=graphene.String(required=True)) + film_details = graphene.Field( + FilmDetailsType, location=graphene.String(required=True) + ) + + def resolve_film(self, info, genre): + return Film.objects.filter(genre=genre).first() + + def resolve_film_details(self, info, location): + return FilmDetails.objects.filter(location=location).first() + + schema = graphene.Schema(query=Query) + + Film.objects.create(genre="do") + FilmDetails.objects.create(location="London") + + query_film = """ + query getFilm($genre: String!) { + film(genre: $genre) { + genre + details { + location + } + } + } + """ + + query_film_details = """ + query getFilmDetails($location: String!) { + filmDetails(location: $location) { + location + film { + genre + } + } + } + """ + + result = schema.execute(query_film, variables={"genre": "do"}) + assert not result.errors + assert result.data["film"] == { + "genre": "DO", + "details": None, + } + + result = schema.execute(query_film_details, variables={"location": "London"}) + assert not result.errors + assert result.data["filmDetails"] == { + "location": "London", + "film": None, + }