From b08f2d6fafda6e1e37c8e919f806bee0db17edd8 Mon Sep 17 00:00:00 2001 From: Tom Dror Date: Mon, 19 Dec 2022 13:10:02 -0500 Subject: [PATCH 1/6] support reverse relationship for proxy models --- graphene_django/tests/test_query.py | 104 ++++++++++++++++++++++++++++ graphene_django/tests/test_utils.py | 11 ++- graphene_django/utils/utils.py | 28 +++++--- 3 files changed, 130 insertions(+), 13 deletions(-) diff --git a/graphene_django/tests/test_query.py b/graphene_django/tests/test_query.py index df339d877..87cc3e084 100644 --- a/graphene_django/tests/test_query.py +++ b/graphene_django/tests/test_query.py @@ -1067,6 +1067,110 @@ class Query(graphene.ObjectType): assert result.data == expected +def test_proxy_model_support_reverse_relationships(): + """ + This test asserts that we can query reverse relationships for all Reporters and proxied Reporters. + """ + + class FilmType(DjangoObjectType): + class Meta: + model = Film + fields = "__all__" + + class ReporterType(DjangoObjectType): + class Meta: + model = Reporter + interfaces = (Node,) + use_connection = True + fields = "__all__" + + class CNNReporterType(DjangoObjectType): + class Meta: + model = CNNReporter + interfaces = (Node,) + use_connection = True + fields = "__all__" + + film = Film.objects.create(genre="do") + + reporter = Reporter.objects.create( + first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1 + ) + + cnn_reporter = CNNReporter.objects.create( + first_name="Some", + last_name="Guy", + email="someguy@cnn.com", + a_choice=1, + reporter_type=2, # set this guy to be CNN + ) + + film.reporters.add(cnn_reporter) + film.save() + + class Query(graphene.ObjectType): + all_reporters = DjangoConnectionField(ReporterType) + cnn_reporters = DjangoConnectionField(CNNReporterType) + + schema = graphene.Schema(query=Query) + query = """ + query ProxyModelQuery { + allReporters { + edges { + node { + id + films { + id + } + } + } + } + cnnReporters { + edges { + node { + id + films { + id + } + } + } + } + } + """ + + expected = { + "allReporters": { + "edges": [ + { + "node": { + "id": to_global_id("ReporterType", reporter.id), + "films": [], + }, + }, + { + "node": { + "id": to_global_id("ReporterType", cnn_reporter.id), + "films": [{"id": f"{film.id}"}], + }, + }, + ] + }, + "cnnReporters": { + "edges": [ + { + "node": { + "id": to_global_id("CNNReporterType", cnn_reporter.id), + "films": [{"id": f"{film.id}"}], + } + } + ] + }, + } + + result = schema.execute(query) + assert result.data == expected + + def test_should_resolve_get_queryset_connectionfields(): reporter_1 = Reporter.objects.create( first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1 diff --git a/graphene_django/tests/test_utils.py b/graphene_django/tests/test_utils.py index fa269b44c..22f87c7f0 100644 --- a/graphene_django/tests/test_utils.py +++ b/graphene_django/tests/test_utils.py @@ -4,8 +4,8 @@ from django.utils.translation import gettext_lazy from unittest.mock import patch -from ..utils import camelize, get_model_fields, GraphQLTestCase -from .models import Film, Reporter +from ..utils import camelize, get_model_fields, get_reverse_fields, GraphQLTestCase +from .models import Film, Reporter, CNNReporter from ..utils.testing import graphql_query @@ -19,6 +19,13 @@ def test_get_model_fields_no_duplication(): assert len(film_fields) == len(film_name_set) +def test_get_reverse_fields_includes_proxied_models(): + reporter_fields = get_reverse_fields(Reporter, []) + cnn_reporter_fields = get_reverse_fields(CNNReporter, []) + + assert len(list(reporter_fields)) == len(list(cnn_reporter_fields)) + + def test_camelize(): assert camelize({}) == {} assert camelize("value_a") == "value_a" diff --git a/graphene_django/utils/utils.py b/graphene_django/utils/utils.py index 343a3a74c..228b41aee 100644 --- a/graphene_django/utils/utils.py +++ b/graphene_django/utils/utils.py @@ -38,17 +38,23 @@ def camelize(data): def get_reverse_fields(model, local_field_names): - for name, attr in model.__dict__.items(): - # Don't duplicate any local fields - if name in local_field_names: - continue - - # "rel" for FK and M2M relations and "related" for O2O Relations - related = getattr(attr, "rel", None) or getattr(attr, "related", None) - if isinstance(related, models.ManyToOneRel): - yield (name, related) - elif isinstance(related, models.ManyToManyRel) and not related.symmetrical: - yield (name, related) + model_ancestry = [model] + # Include proxy models when getting related fields + if model._meta.proxy: + model_ancestry.append(model._meta.proxy_for_model) + + for _model in model_ancestry: + for name, attr in _model.__dict__.items(): + # Don't duplicate any local fields + if name in local_field_names: + continue + + # "rel" for FK and M2M relations and "related" for O2O Relations + related = getattr(attr, "rel", None) or getattr(attr, "related", None) + if isinstance(related, models.ManyToOneRel): + yield (name, related) + elif isinstance(related, models.ManyToManyRel) and not related.symmetrical: + yield (name, related) def maybe_queryset(value): From d009f3502eb142adc28e734e68aea3546c1e1525 Mon Sep 17 00:00:00 2001 From: Tom Dror Date: Tue, 10 Jan 2023 12:50:01 -0500 Subject: [PATCH 2/6] support multi table inheritence --- graphene_django/tests/models.py | 8 ++++++++ graphene_django/tests/test_schema.py | 4 ++-- graphene_django/tests/test_types.py | 4 ++-- graphene_django/tests/test_utils.py | 5 +++-- graphene_django/utils/utils.py | 7 ++++--- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/graphene_django/tests/models.py b/graphene_django/tests/models.py index 636f74c6d..705cedf50 100644 --- a/graphene_django/tests/models.py +++ b/graphene_django/tests/models.py @@ -89,6 +89,14 @@ class Meta: objects = CNNReporterManager() +class APNewsReporter(Reporter): + """ + This class only inherits from Reporter for testing multi table inheritence + similar to what you'd see in django-polymorphic + """ + alias = models.CharField(max_length=30) + objects = models.Manager() + class Article(models.Model): headline = models.CharField(max_length=100) diff --git a/graphene_django/tests/test_schema.py b/graphene_django/tests/test_schema.py index ff2d8a668..88cabe986 100644 --- a/graphene_django/tests/test_schema.py +++ b/graphene_django/tests/test_schema.py @@ -33,7 +33,7 @@ class Meta: fields = "__all__" fields = list(ReporterType2._meta.fields.keys()) - assert fields[:-2] == [ + assert fields[:-3] == [ "id", "first_name", "last_name", @@ -43,7 +43,7 @@ class Meta: "reporter_type", ] - assert sorted(fields[-2:]) == ["articles", "films"] + assert sorted(fields[-3:]) == ["apnewsreporter", "articles", "films"] def test_should_map_only_few_fields(): diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index fad26e2ab..7d75267a5 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -67,7 +67,7 @@ def test_django_get_node(get): def test_django_objecttype_map_correct_fields(): fields = Reporter._meta.fields fields = list(fields.keys()) - assert fields[:-2] == [ + assert fields[:-3] == [ "id", "first_name", "last_name", @@ -76,7 +76,7 @@ def test_django_objecttype_map_correct_fields(): "a_choice", "reporter_type", ] - assert sorted(fields[-2:]) == ["articles", "films"] + assert sorted(fields[-3:]) == ["apnewsreporter", "articles", "films"] def test_django_objecttype_with_node_have_correct_fields(): diff --git a/graphene_django/tests/test_utils.py b/graphene_django/tests/test_utils.py index 22f87c7f0..5a4db8d73 100644 --- a/graphene_django/tests/test_utils.py +++ b/graphene_django/tests/test_utils.py @@ -5,7 +5,7 @@ from unittest.mock import patch from ..utils import camelize, get_model_fields, get_reverse_fields, GraphQLTestCase -from .models import Film, Reporter, CNNReporter +from .models import Film, Reporter, CNNReporter, APNewsReporter from ..utils.testing import graphql_query @@ -22,8 +22,9 @@ def test_get_model_fields_no_duplication(): def test_get_reverse_fields_includes_proxied_models(): reporter_fields = get_reverse_fields(Reporter, []) cnn_reporter_fields = get_reverse_fields(CNNReporter, []) + ap_news_reporter_fields = get_reverse_fields(APNewsReporter, []) - assert len(list(reporter_fields)) == len(list(cnn_reporter_fields)) + assert len(list(reporter_fields)) == len(list(cnn_reporter_fields)) == len(list(ap_news_reporter_fields)) def test_camelize(): diff --git a/graphene_django/utils/utils.py b/graphene_django/utils/utils.py index 228b41aee..51abeb564 100644 --- a/graphene_django/utils/utils.py +++ b/graphene_django/utils/utils.py @@ -39,9 +39,10 @@ def camelize(data): def get_reverse_fields(model, local_field_names): model_ancestry = [model] - # Include proxy models when getting related fields - if model._meta.proxy: - model_ancestry.append(model._meta.proxy_for_model) + + for base in model.__bases__: + if is_valid_django_model(base): + model_ancestry.append(base) for _model in model_ancestry: for name, attr in _model.__dict__.items(): From 54f48b3e991a09c8f3f7879b77750a0910c7d472 Mon Sep 17 00:00:00 2001 From: Tom Dror Date: Tue, 10 Jan 2023 13:04:59 -0500 Subject: [PATCH 3/6] update query test for multi table inheritance --- graphene_django/tests/test_query.py | 47 ++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/graphene_django/tests/test_query.py b/graphene_django/tests/test_query.py index 87cc3e084..390878988 100644 --- a/graphene_django/tests/test_query.py +++ b/graphene_django/tests/test_query.py @@ -15,7 +15,7 @@ from ..fields import DjangoConnectionField from ..types import DjangoObjectType from ..utils import DJANGO_FILTER_INSTALLED -from .models import Article, CNNReporter, Film, FilmDetails, Person, Pet, Reporter +from .models import Article, CNNReporter, Film, FilmDetails, Person, Pet, Reporter, APNewsReporter def test_should_query_only_fields(): @@ -1067,9 +1067,9 @@ class Query(graphene.ObjectType): assert result.data == expected -def test_proxy_model_support_reverse_relationships(): +def test_model_inheritance_support_reverse_relationships(): """ - This test asserts that we can query reverse relationships for all Reporters and proxied Reporters. + This test asserts that we can query reverse relationships for all Reporters and proxied Reporters and multi table Reporters. """ class FilmType(DjangoObjectType): @@ -1090,6 +1090,13 @@ class Meta: interfaces = (Node,) use_connection = True fields = "__all__" + + class APNewsReporterType(DjangoObjectType): + class Meta: + model = APNewsReporter + interfaces = (Node,) + use_connection = True + fields = "__all__" film = Film.objects.create(genre="do") @@ -1105,12 +1112,17 @@ class Meta: reporter_type=2, # set this guy to be CNN ) - film.reporters.add(cnn_reporter) + ap_news_reporter = APNewsReporter.objects.create( + first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1 + ) + + film.reporters.add(cnn_reporter, ap_news_reporter) film.save() class Query(graphene.ObjectType): all_reporters = DjangoConnectionField(ReporterType) cnn_reporters = DjangoConnectionField(CNNReporterType) + ap_news_reporters = DjangoConnectionField(APNewsReporterType) schema = graphene.Schema(query=Query) query = """ @@ -1135,9 +1147,20 @@ class Query(graphene.ObjectType): } } } + apNewsReporters { + edges { + node { + id + films { + id + } + } + } + } } """ + import pdb; pdb.set_trace() expected = { "allReporters": { "edges": [ @@ -1153,6 +1176,12 @@ class Query(graphene.ObjectType): "films": [{"id": f"{film.id}"}], }, }, + { + "node": { + "id": to_global_id("ReporterType", ap_news_reporter.id), + "films": [{"id": f"{film.id}"}], + }, + }, ] }, "cnnReporters": { @@ -1165,6 +1194,16 @@ class Query(graphene.ObjectType): } ] }, + "apNewsReporters": { + "edges": [ + { + "node": { + "id": to_global_id("APNewsReporterType", ap_news_reporter.id), + "films": [{"id": f"{film.id}"}], + } + } + ] + }, } result = schema.execute(query) From 50ebf76789c6858318a4d41067420431ab9bfa25 Mon Sep 17 00:00:00 2001 From: Tom Dror Date: Tue, 10 Jan 2023 15:08:34 -0500 Subject: [PATCH 4/6] remove debugger --- graphene_django/tests/test_query.py | 1 - 1 file changed, 1 deletion(-) diff --git a/graphene_django/tests/test_query.py b/graphene_django/tests/test_query.py index 390878988..43e7d5431 100644 --- a/graphene_django/tests/test_query.py +++ b/graphene_django/tests/test_query.py @@ -1160,7 +1160,6 @@ class Query(graphene.ObjectType): } """ - import pdb; pdb.set_trace() expected = { "allReporters": { "edges": [ From 264b84aed88b3ef77621e5b9c366aec73f402947 Mon Sep 17 00:00:00 2001 From: Tom Dror Date: Tue, 10 Jan 2023 19:41:57 -0500 Subject: [PATCH 5/6] support local many to many in model inheritance --- graphene_django/tests/models.py | 1 + graphene_django/tests/test_query.py | 161 ++++++++++++++++++++++++++- graphene_django/tests/test_schema.py | 1 + graphene_django/tests/test_types.py | 1 + graphene_django/utils/utils.py | 48 ++++++-- 5 files changed, 199 insertions(+), 13 deletions(-) diff --git a/graphene_django/tests/models.py b/graphene_django/tests/models.py index 705cedf50..69b9a9535 100644 --- a/graphene_django/tests/models.py +++ b/graphene_django/tests/models.py @@ -46,6 +46,7 @@ class Reporter(models.Model): a_choice = models.CharField(max_length=30, choices=CHOICES, blank=True) objects = models.Manager() doe_objects = DoeReporterManager() + fans = models.ManyToManyField(Person) reporter_type = models.IntegerField( "Reporter Type", diff --git a/graphene_django/tests/test_query.py b/graphene_django/tests/test_query.py index 43e7d5431..a01e0177f 100644 --- a/graphene_django/tests/test_query.py +++ b/graphene_django/tests/test_query.py @@ -1076,7 +1076,7 @@ class FilmType(DjangoObjectType): class Meta: model = Film fields = "__all__" - + class ReporterType(DjangoObjectType): class Meta: model = Reporter @@ -1209,6 +1209,165 @@ class Query(graphene.ObjectType): assert result.data == expected +def test_model_inheritance_support_local_relationships(): + """ + This test asserts that we can query local relationships for all Reporters and proxied Reporters and multi table Reporters. + """ + + class PersonType(DjangoObjectType): + class Meta: + model = Person + fields = "__all__" + + class ReporterType(DjangoObjectType): + class Meta: + model = Reporter + interfaces = (Node,) + use_connection = True + fields = "__all__" + + class CNNReporterType(DjangoObjectType): + class Meta: + model = CNNReporter + interfaces = (Node,) + use_connection = True + fields = "__all__" + + class APNewsReporterType(DjangoObjectType): + class Meta: + model = APNewsReporter + interfaces = (Node,) + use_connection = True + fields = "__all__" + + film = Film.objects.create(genre="do") + + reporter = Reporter.objects.create( + first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1 + ) + + + reporter_fan = Person.objects.create( + name="Reporter Fan" + ) + + reporter.fans.add(reporter_fan) + reporter.save() + + cnn_reporter = CNNReporter.objects.create( + first_name="Some", + last_name="Guy", + email="someguy@cnn.com", + a_choice=1, + reporter_type=2, # set this guy to be CNN + ) + cnn_fan = Person.objects.create( + name="CNN Fan" + ) + cnn_reporter.fans.add(cnn_fan) + cnn_reporter.save() + + ap_news_reporter = APNewsReporter.objects.create( + first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1 + ) + ap_news_fan = Person.objects.create( + name="AP News Fan" + ) + ap_news_reporter.fans.add(ap_news_fan) + ap_news_reporter.save() + + film.reporters.add(cnn_reporter, ap_news_reporter) + film.save() + + class Query(graphene.ObjectType): + all_reporters = DjangoConnectionField(ReporterType) + cnn_reporters = DjangoConnectionField(CNNReporterType) + ap_news_reporters = DjangoConnectionField(APNewsReporterType) + + schema = graphene.Schema(query=Query) + query = """ + query ProxyModelQuery { + allReporters { + edges { + node { + id + fans { + name + } + } + } + } + cnnReporters { + edges { + node { + id + fans { + name + } + } + } + } + apNewsReporters { + edges { + node { + id + fans { + name + } + } + } + } + } + """ + + expected = { + "allReporters": { + "edges": [ + { + "node": { + "id": to_global_id("ReporterType", reporter.id), + "fans": [{"name": f"{reporter_fan.name}"}], + }, + }, + { + "node": { + "id": to_global_id("ReporterType", cnn_reporter.id), + "fans": [{"name": f"{cnn_fan.name}"}], + }, + }, + { + "node": { + "id": to_global_id("ReporterType", ap_news_reporter.id), + "fans": [{"name": f"{ap_news_fan.name}"}], + }, + }, + ] + }, + "cnnReporters": { + "edges": [ + { + "node": { + "id": to_global_id("CNNReporterType", cnn_reporter.id), + "fans": [{"name": f"{cnn_fan.name}"}], + } + } + ] + }, + "apNewsReporters": { + "edges": [ + { + "node": { + "id": to_global_id("APNewsReporterType", ap_news_reporter.id), + "fans": [{"name": f"{ap_news_fan.name}"}], + } + } + ] + }, + } + + result = schema.execute(query) + assert result.data == expected + def test_should_resolve_get_queryset_connectionfields(): reporter_1 = Reporter.objects.create( first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1 diff --git a/graphene_django/tests/test_schema.py b/graphene_django/tests/test_schema.py index 88cabe986..93cbd9f05 100644 --- a/graphene_django/tests/test_schema.py +++ b/graphene_django/tests/test_schema.py @@ -40,6 +40,7 @@ class Meta: "email", "pets", "a_choice", + "fans", "reporter_type", ] diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index 7d75267a5..fd85ef140 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -74,6 +74,7 @@ def test_django_objecttype_map_correct_fields(): "email", "pets", "a_choice", + "fans", "reporter_type", ] assert sorted(fields[-3:]) == ["apnewsreporter", "articles", "films"] diff --git a/graphene_django/utils/utils.py b/graphene_django/utils/utils.py index 51abeb564..84f88b6c5 100644 --- a/graphene_django/utils/utils.py +++ b/graphene_django/utils/utils.py @@ -37,12 +37,21 @@ def camelize(data): return data -def get_reverse_fields(model, local_field_names): +def _get_model_ancestry(model): model_ancestry = [model] for base in model.__bases__: - if is_valid_django_model(base): + if is_valid_django_model(base) and getattr(base, "_meta", False): model_ancestry.append(base) + return model_ancestry + + +def get_reverse_fields(model, local_field_names): + """ + Searches through the model's ancestry and gets reverse relationships the models + Yields a tuple of (field.name, field) + """ + model_ancestry = _get_model_ancestry(model) for _model in model_ancestry: for name, attr in _model.__dict__.items(): @@ -58,6 +67,24 @@ def get_reverse_fields(model, local_field_names): yield (name, related) +def get_local_fields(model): + """ + Searches through the model's ancestry and gets the fields on the models + Returns a dict of {field.name: field} + """ + model_ancestry = _get_model_ancestry(model) + + local_fields_dict = {} + for _model in model_ancestry: + for field in sorted( + list(_model._meta.fields) + list(_model._meta.local_many_to_many) + ): + if field.name not in local_fields_dict: + local_fields_dict[field.name] = field + + return list(local_fields_dict.items()) + + def maybe_queryset(value): if isinstance(value, Manager): value = value.get_queryset() @@ -65,17 +92,14 @@ def maybe_queryset(value): def get_model_fields(model): - local_fields = [ - (field.name, field) - for field in sorted( - list(model._meta.fields) + list(model._meta.local_many_to_many) - ) - ] - - # Make sure we don't duplicate local fields with "reverse" version - local_field_names = [field[0] for field in local_fields] + """ + Gets all the fields and relationships on the Django model and its ancestry. + Prioritizes local fields and relationships over the reverse relationships of the same name + Returns a tuple of (field.name, field) + """ + local_fields = get_local_fields(model) + local_field_names = {field[0] for field in local_fields} reverse_fields = get_reverse_fields(model, local_field_names) - all_fields = local_fields + list(reverse_fields) return all_fields From 6ae636230ca9de671468688aff6b9e0b969e4045 Mon Sep 17 00:00:00 2001 From: Tom Dror Date: Tue, 10 Jan 2023 20:00:04 -0500 Subject: [PATCH 6/6] format and lint --- graphene_django/tests/models.py | 2 ++ graphene_django/tests/test_query.py | 33 ++++++++++++++++------------- graphene_django/tests/test_utils.py | 6 +++++- graphene_django/utils/utils.py | 2 +- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/graphene_django/tests/models.py b/graphene_django/tests/models.py index 69b9a9535..085a508c7 100644 --- a/graphene_django/tests/models.py +++ b/graphene_django/tests/models.py @@ -90,11 +90,13 @@ class Meta: objects = CNNReporterManager() + class APNewsReporter(Reporter): """ This class only inherits from Reporter for testing multi table inheritence similar to what you'd see in django-polymorphic """ + alias = models.CharField(max_length=30) objects = models.Manager() diff --git a/graphene_django/tests/test_query.py b/graphene_django/tests/test_query.py index a01e0177f..292d5790b 100644 --- a/graphene_django/tests/test_query.py +++ b/graphene_django/tests/test_query.py @@ -15,7 +15,16 @@ from ..fields import DjangoConnectionField from ..types import DjangoObjectType from ..utils import DJANGO_FILTER_INSTALLED -from .models import Article, CNNReporter, Film, FilmDetails, Person, Pet, Reporter, APNewsReporter +from .models import ( + Article, + CNNReporter, + Film, + FilmDetails, + Person, + Pet, + Reporter, + APNewsReporter, +) def test_should_query_only_fields(): @@ -1076,7 +1085,7 @@ class FilmType(DjangoObjectType): class Meta: model = Film fields = "__all__" - + class ReporterType(DjangoObjectType): class Meta: model = Reporter @@ -1090,7 +1099,7 @@ class Meta: interfaces = (Node,) use_connection = True fields = "__all__" - + class APNewsReporterType(DjangoObjectType): class Meta: model = APNewsReporter @@ -1213,7 +1222,7 @@ def test_model_inheritance_support_local_relationships(): """ This test asserts that we can query local relationships for all Reporters and proxied Reporters and multi table Reporters. """ - + class PersonType(DjangoObjectType): class Meta: model = Person @@ -1232,7 +1241,7 @@ class Meta: interfaces = (Node,) use_connection = True fields = "__all__" - + class APNewsReporterType(DjangoObjectType): class Meta: model = APNewsReporter @@ -1246,10 +1255,7 @@ class Meta: first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1 ) - - reporter_fan = Person.objects.create( - name="Reporter Fan" - ) + reporter_fan = Person.objects.create(name="Reporter Fan") reporter.fans.add(reporter_fan) reporter.save() @@ -1261,18 +1267,14 @@ class Meta: a_choice=1, reporter_type=2, # set this guy to be CNN ) - cnn_fan = Person.objects.create( - name="CNN Fan" - ) + cnn_fan = Person.objects.create(name="CNN Fan") cnn_reporter.fans.add(cnn_fan) cnn_reporter.save() ap_news_reporter = APNewsReporter.objects.create( first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1 ) - ap_news_fan = Person.objects.create( - name="AP News Fan" - ) + ap_news_fan = Person.objects.create(name="AP News Fan") ap_news_reporter.fans.add(ap_news_fan) ap_news_reporter.save() @@ -1368,6 +1370,7 @@ class Query(graphene.ObjectType): result = schema.execute(query) assert result.data == expected + def test_should_resolve_get_queryset_connectionfields(): reporter_1 = Reporter.objects.create( first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1 diff --git a/graphene_django/tests/test_utils.py b/graphene_django/tests/test_utils.py index 5a4db8d73..4e6861eda 100644 --- a/graphene_django/tests/test_utils.py +++ b/graphene_django/tests/test_utils.py @@ -24,7 +24,11 @@ def test_get_reverse_fields_includes_proxied_models(): cnn_reporter_fields = get_reverse_fields(CNNReporter, []) ap_news_reporter_fields = get_reverse_fields(APNewsReporter, []) - assert len(list(reporter_fields)) == len(list(cnn_reporter_fields)) == len(list(ap_news_reporter_fields)) + assert ( + len(list(reporter_fields)) + == len(list(cnn_reporter_fields)) + == len(list(ap_news_reporter_fields)) + ) def test_camelize(): diff --git a/graphene_django/utils/utils.py b/graphene_django/utils/utils.py index 84f88b6c5..187442cdd 100644 --- a/graphene_django/utils/utils.py +++ b/graphene_django/utils/utils.py @@ -81,7 +81,7 @@ def get_local_fields(model): ): if field.name not in local_fields_dict: local_fields_dict[field.name] = field - + return list(local_fields_dict.items())