diff --git a/graphene_django/fields.py b/graphene_django/fields.py index 92e08623..12ed9e62 100644 --- a/graphene_django/fields.py +++ b/graphene_django/fields.py @@ -30,17 +30,20 @@ class DjangoListField(Field): def __init__(self, _type, *args, **kwargs): - from .types import DjangoObjectType - if isinstance(_type, NonNull): _type = _type.of_type # Django would never return a Set of None super().__init__(List(NonNull(_type)), *args, **kwargs) + @property + def type(self): + from .types import DjangoObjectType + assert issubclass( self._underlying_type, DjangoObjectType - ), "DjangoListField only accepts DjangoObjectType types" + ), "DjangoListField only accepts DjangoObjectType types as underlying type" + return super().type @property def _underlying_type(self): @@ -92,19 +95,22 @@ def __init__( *args, **kwargs, ): - from graphene_django.types import DjangoObjectType - if isinstance(_type, NonNull): _type = _type.of_type # Django would never return a Set of None super().__init__(List(NonNull(_type)), *args, **kwargs) + self._field = field + + @property + def type(self): + from .types import DjangoObjectType + assert issubclass( self._underlying_type, DjangoObjectType - ), "DjangoListField only accepts DjangoObjectType types" - - self._field = field + ), "DjangoDataloadedListField only accepts DjangoObjectType types as underlying type" + return super().type @property def _underlying_type(self): diff --git a/graphene_django/tests/models.py b/graphene_django/tests/models.py index 44ed38e5..b966d4fe 100644 --- a/graphene_django/tests/models.py +++ b/graphene_django/tests/models.py @@ -6,6 +6,9 @@ class Person(models.Model): name = models.CharField(max_length=30) + parent = models.ForeignKey( + "self", on_delete=models.CASCADE, null=True, blank=True, related_name="children" + ) class Pet(models.Model): diff --git a/graphene_django/tests/test_fields.py b/graphene_django/tests/test_fields.py index a313a6f9..e5135b5d 100644 --- a/graphene_django/tests/test_fields.py +++ b/graphene_django/tests/test_fields.py @@ -13,17 +13,18 @@ Article as ArticleModel, Film as FilmModel, FilmDetails as FilmDetailsModel, + Person as PersonModel, Reporter as ReporterModel, ) class TestDjangoListField: def test_only_django_object_types(self): - class TestType(ObjectType): - foo = String() + class Query(ObjectType): + something = DjangoListField(String) - with pytest.raises(AssertionError): - DjangoListField(TestType) + with pytest.raises(TypeError): + Schema(query=Query) def test_only_import_paths(self): list_field = DjangoListField("graphene_django.tests.schema.Human") @@ -263,6 +264,69 @@ class Query(ObjectType): ] } + def test_same_type_nested_list_field(self): + class Person(DjangoObjectType): + class Meta: + model = PersonModel + fields = ("name", "parent") + + children = DjangoListField(lambda: Person) + + class Query(ObjectType): + persons = DjangoListField(Person) + + schema = Schema(query=Query) + + query = """ + query { + persons { + name + children { + name + } + } + } + """ + + p1 = PersonModel.objects.create(name="Tara") + PersonModel.objects.create(name="Debra") + + PersonModel.objects.create( + name="Toto", + parent=p1, + ) + PersonModel.objects.create( + name="Tata", + parent=p1, + ) + + result = schema.execute(query) + + assert not result.errors + assert result.data == { + "persons": [ + { + "name": "Tara", + "children": [ + {"name": "Toto"}, + {"name": "Tata"}, + ], + }, + { + "name": "Debra", + "children": [], + }, + { + "name": "Toto", + "children": [], + }, + { + "name": "Tata", + "children": [], + }, + ] + } + def test_get_queryset_filter(self): class Reporter(DjangoObjectType): class Meta: