Repository: graphql-python/graphene-django

Issue:
custom @classmethod get_queryset of DjangoObjectType not works
in official docs: https://docs.graphene-python.org/projects/django/en/latest/queries/#default-queryset. In practice nothing happens. Please help


Discussion:
Here's the unit test for this feature: https://github.com/graphql-python/graphene-django/blob/master/graphene_django/tests/test_query.py#L1026

Maybe you can show us how you defined your object type?
@zbyte64 a lot of thanks for your feedback!

```
class ContactType(DjangoObjectType):
    class Meta:
        model = Contact

    @classmethod
    def get_queryset(cls, queryset, info):
        return queryset.filter(kind='PHONE')

class ContactQuery(graphene.ObjectType):
    contacts = graphene.List(ContactType)

    def resolve_contacts(self, info, **kwargs):
        return Contact.objects.all()
```

The query:

```
{
    contacts {
        id
        kind
        value
    }
}
```

returns:

```
{
  "data": {
    "contacts": [
      {
        "id": "1",
        "kind": "INSTAGRAM",
        "value": "technodomkz"
      },
      {
        "id": "3",
        "kind": "YOUTUBE",
        "value": "UCF-HjvMMvgnhXhO4shk9i9Q"
      },
      {
        "id": "4",
        "kind": "FACEBOOK",
        "value": "technodomkz"
      },
      {
        "id": "5",
        "kind": "TWITTER",
        "value": "technodom_kz"
      },
      {
        "id": "6",
        "kind": "PHONE",
        "value": "88000801111"
      },
      {
        "id": "7",
        "kind": "PHONE",
        "value": "87272799999"
      },
      {
        "id": "8",
        "kind": "EMAIL",
        "value": "callcenter@technodom.kz"
      },
      {
        "id": "2",
        "kind": "WEBSITE",
        "value": "www.technodom.kz"
      }
    ]
  }
}
```

instead of:

```
{
  "data": {
    "contacts": [
      {
        "id": "6",
        "kind": "PHONE",
        "value": "88000801111"
      },
      {
        "id": "7",
        "kind": "PHONE",
        "value": "87272799999"
      }
    ]
  }
}
```
Try swapping out `List` for `DjangoConnectionField`.
Looks like we need to document that `get_queryset` works with the `DjangoConnectionField` and that non-relay fields like `List` don't have the same magic.

It works DjangoConnectionField, thanks! Yeah it needs to correct the document or just do same magic with List ))
@zbyte64 is it generally possible to do this with graphene.List? For example i need to fetch all companies with flag that authorized user subscribed it or not.
```
class SubscriptionType(DjangoObjectType):
    class Meta:
        model = Subscription

    @classmethod
    def get_queryset(cls, queryset, info):
        return queryset.filter(client=info.context.user.client)
```
and then, I could request:
```
query {
    companies {
        id
        otherFields,
        subscriptions {
            id
            subscribedTime
        }
    }
}
```
and I will know that if company has not empty field 'subscriptions', auth user subscribed this company.
Of course I can set the queryset on the endpoint like:
```
class CompanyQuery(graphene.ObjectType):
    companies = DjangoListField(CompanyType)

    def resolve_companies(self, info, **kwargs):
        return Company.objects.prefetch_related(
            Prefetch('subscriptions', queryset=Subscription.objects.filter(client=info.context.user.client))
        )
```
But what about queries like:
```
query {
    programs {
        company {
            subscribers {
                id
            }
        }
    }

    points {
        company {
            subscribers {
                id
            }
        }
    }
}
```
I have some more models that have relations with company model. It's crazy do the filter to querysets for all endpoints(programs, points, etc)
Perhaps there is another way to the solution of this problem? Cause I quite recently started working with graphene !?
I think the `resolve_foo` methods gets called when you do nested queries. So you can do auth restriction there for each one. Is there a reason why you don't want to use `DjangoFilterConnectionField`?
@dan-klasson thank you for feedback. The main reason why i don't want use DjangoFilterConnectionField is edges-node conception 
@abtuleshov I've create a PR that extends `DjangoListField` to behaviour how you would expect in your examples: https://github.com/graphql-python/graphene-django/pull/732
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@jkimbo @abtuleshov is this indeed fixed with PR #732? I can't get it to work:

```
class CurrencyType(DjangoObjectType):
    class Meta:
        model = Currency

    @classmethod
    def get_queryset(cls, queryset, info):
        print(cls)
        print(queryset)
        return queryset.filter(symbol__isnull=False)
```

```
all_currencies = graphene.List(CurrencyType)

def resolve_all_currencies(self, info):
    return Currency.objects.all()
```

The `get_queryset` method is never called, and the filter is not applied.

> I think the `resolve_foo` methods gets called when you do nested queries. So you can do auth restriction there for each one. 

@dan-klasson, unfortunately, the `resolve_foo` methods are not called on `related_name` fields.


@pors yeah before it's worked fine with, with PR by @jkimbo, but with the latest updates, get_queryset just began to ignore. It's a shame that everything is done for the sake of relay, but ordinary people have to hardcode )
@abtuleshov thanks for the reply! Do you know which release or commit broke it again? Maybe I can fix it and create a PR.
I abandoned that project for a some time, I think it was a 2.5.0 or 2.6.0  version

Resolving patch:
diff --git a/graphene_django/__init__.py b/graphene_django/__init__.py
--- a/graphene_django/__init__.py
+++ b/graphene_django/__init__.py
@@ -1,6 +1,11 @@
+from .fields import DjangoConnectionField, DjangoListField
 from .types import DjangoObjectType
-from .fields import DjangoConnectionField
 
 __version__ = "2.9.1"
 
-__all__ = ["__version__", "DjangoObjectType", "DjangoConnectionField"]
+__all__ = [
+    "__version__",
+    "DjangoObjectType",
+    "DjangoListField",
+    "DjangoConnectionField",
+]
diff --git a/graphene_django/fields.py b/graphene_django/fields.py
--- a/graphene_django/fields.py
+++ b/graphene_django/fields.py
@@ -38,16 +38,21 @@ def _underlying_type(self):
     def model(self):
         return self._underlying_type._meta.model
 
+    def get_default_queryset(self):
+        return self.model._default_manager.get_queryset()
+
     @staticmethod
-    def list_resolver(django_object_type, resolver, root, info, **args):
+    def list_resolver(
+        django_object_type, resolver, default_queryset, root, info, **args
+    ):
         queryset = maybe_queryset(resolver(root, info, **args))
         if queryset is None:
-            # Default to Django Model queryset
-            # N.B. This happens if DjangoListField is used in the top level Query object
-            model_manager = django_object_type._meta.model.objects
-            queryset = maybe_queryset(
-                django_object_type.get_queryset(model_manager, info)
-            )
+            queryset = default_queryset
+
+        if isinstance(queryset, QuerySet):
+            # Pass queryset to the DjangoObjectType get_queryset method
+            queryset = maybe_queryset(django_object_type.get_queryset(queryset, info))
+
         return queryset
 
     def get_resolver(self, parent_resolver):
@@ -55,7 +60,12 @@ def get_resolver(self, parent_resolver):
         if isinstance(_type, NonNull):
             _type = _type.of_type
         django_object_type = _type.of_type.of_type
-        return partial(self.list_resolver, django_object_type, parent_resolver)
+        return partial(
+            self.list_resolver,
+            django_object_type,
+            parent_resolver,
+            self.get_default_queryset(),
+        )
 
 
 class DjangoConnectionField(ConnectionField):


Test patch:
diff --git a/graphene_django/tests/test_fields.py b/graphene_django/tests/test_fields.py
--- a/graphene_django/tests/test_fields.py
+++ b/graphene_django/tests/test_fields.py
@@ -1,4 +1,5 @@
 import datetime
+from django.db.models import Count
 
 import pytest
 
@@ -141,13 +142,26 @@ class Query(ObjectType):
             pub_date_time=datetime.datetime.now(),
             editor=r1,
         )
+        ArticleModel.objects.create(
+            headline="Not so good news",
+            reporter=r1,
+            pub_date=datetime.date.today(),
+            pub_date_time=datetime.datetime.now(),
+            editor=r1,
+        )
 
         result = schema.execute(query)
 
         assert not result.errors
         assert result.data == {
             "reporters": [
-                {"firstName": "Tara", "articles": [{"headline": "Amazing news"}]},
+                {
+                    "firstName": "Tara",
+                    "articles": [
+                        {"headline": "Amazing news"},
+                        {"headline": "Not so good news"},
+                    ],
+                },
                 {"firstName": "Debra", "articles": []},
             ]
         }
@@ -163,8 +177,8 @@ class Meta:
                 model = ReporterModel
                 fields = ("first_name", "articles")
 
-            def resolve_reporters(reporter, info):
-                return reporter.articles.all()
+            def resolve_articles(reporter, info):
+                return reporter.articles.filter(headline__contains="Amazing")
 
         class Query(ObjectType):
             reporters = DjangoListField(Reporter)
@@ -192,6 +206,13 @@ class Query(ObjectType):
             pub_date_time=datetime.datetime.now(),
             editor=r1,
         )
+        ArticleModel.objects.create(
+            headline="Not so good news",
+            reporter=r1,
+            pub_date=datetime.date.today(),
+            pub_date_time=datetime.datetime.now(),
+            editor=r1,
+        )
 
         result = schema.execute(query)
 
@@ -202,3 +223,155 @@ class Query(ObjectType):
                 {"firstName": "Debra", "articles": []},
             ]
         }
+
+    def test_get_queryset_filter(self):
+        class Reporter(DjangoObjectType):
+            class Meta:
+                model = ReporterModel
+                fields = ("first_name", "articles")
+
+            @classmethod
+            def get_queryset(cls, queryset, info):
+                # Only get reporters with at least 1 article
+                return queryset.annotate(article_count=Count("articles")).filter(
+                    article_count__gt=0
+                )
+
+        class Query(ObjectType):
+            reporters = DjangoListField(Reporter)
+
+            def resolve_reporters(_, info):
+                return ReporterModel.objects.all()
+
+        schema = Schema(query=Query)
+
+        query = """
+            query {
+                reporters {
+                    firstName
+                }
+            }
+        """
+
+        r1 = ReporterModel.objects.create(first_name="Tara", last_name="West")
+        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
+
+        ArticleModel.objects.create(
+            headline="Amazing news",
+            reporter=r1,
+            pub_date=datetime.date.today(),
+            pub_date_time=datetime.datetime.now(),
+            editor=r1,
+        )
+
+        result = schema.execute(query)
+
+        assert not result.errors
+        assert result.data == {"reporters": [{"firstName": "Tara"},]}
+
+    def test_resolve_list(self):
+        """Resolving a plain list should work (and not call get_queryset)"""
+
+        class Reporter(DjangoObjectType):
+            class Meta:
+                model = ReporterModel
+                fields = ("first_name", "articles")
+
+            @classmethod
+            def get_queryset(cls, queryset, info):
+                # Only get reporters with at least 1 article
+                return queryset.annotate(article_count=Count("articles")).filter(
+                    article_count__gt=0
+                )
+
+        class Query(ObjectType):
+            reporters = DjangoListField(Reporter)
+
+            def resolve_reporters(_, info):
+                return [ReporterModel.objects.get(first_name="Debra")]
+
+        schema = Schema(query=Query)
+
+        query = """
+            query {
+                reporters {
+                    firstName
+                }
+            }
+        """
+
+        r1 = ReporterModel.objects.create(first_name="Tara", last_name="West")
+        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
+
+        ArticleModel.objects.create(
+            headline="Amazing news",
+            reporter=r1,
+            pub_date=datetime.date.today(),
+            pub_date_time=datetime.datetime.now(),
+            editor=r1,
+        )
+
+        result = schema.execute(query)
+
+        assert not result.errors
+        assert result.data == {"reporters": [{"firstName": "Debra"},]}
+
+    def test_get_queryset_foreign_key(self):
+        class Article(DjangoObjectType):
+            class Meta:
+                model = ArticleModel
+                fields = ("headline",)
+
+            @classmethod
+            def get_queryset(cls, queryset, info):
+                # Rose tinted glasses
+                return queryset.exclude(headline__contains="Not so good")
+
+        class Reporter(DjangoObjectType):
+            class Meta:
+                model = ReporterModel
+                fields = ("first_name", "articles")
+
+        class Query(ObjectType):
+            reporters = DjangoListField(Reporter)
+
+        schema = Schema(query=Query)
+
+        query = """
+            query {
+                reporters {
+                    firstName
+                    articles {
+                        headline
+                    }
+                }
+            }
+        """
+
+        r1 = ReporterModel.objects.create(first_name="Tara", last_name="West")
+        ReporterModel.objects.create(first_name="Debra", last_name="Payne")
+
+        ArticleModel.objects.create(
+            headline="Amazing news",
+            reporter=r1,
+            pub_date=datetime.date.today(),
+            pub_date_time=datetime.datetime.now(),
+            editor=r1,
+        )
+        ArticleModel.objects.create(
+            headline="Not so good news",
+            reporter=r1,
+            pub_date=datetime.date.today(),
+            pub_date_time=datetime.datetime.now(),
+            editor=r1,
+        )
+
+        result = schema.execute(query)
+
+        assert not result.errors
+        assert result.data == {
+            "reporters": [
+                {"firstName": "Tara", "articles": [{"headline": "Amazing news"},],},
+                {"firstName": "Debra", "articles": []},
+            ]
+        }