DjangoConnectionField.resolve_connection replaces resolved queryset with clone, wiping query cache (causing N+1)
See original GitHub issueI’m new to graphene-django so please bear with me if my issue is nonsensical.
I’ve been spending some time trying to figure out why, when using a resolution method in combination with a DjangoFilterConnectionField
any prefetches are being unused. I’ve traced it down to a few things.
Within DjangoFilterConnectionField.merge_querysets
an &
operator is used to merge two Django QuerySet
s. The __and__
method on QuerySet
creates a new instance of its class, thereby losing any internal caching that may have been accomplished when using prefetch_related()
. There doesn’t seem to be much of a way around this without accessing private attributes of the QuerySet
object, which is clearly bad practice.
I then noticed that DjangoConnectionField.resolve_connection
checks to see if iterable is not default_manager
. If it’s not (which as far as I can tell it never will be if you have a resolve_things
method on your Query class) it will then follow down the aforementioned path which winds up wiping cache because it creates a new QuerySet
.
I wonder, what is the purpose of the following code in resolve_connection
? If I disable it, the queryset my resolve_things method returns is actually used and thus the prefetch works.
if iterable is not default_manager:
default_queryset = maybe_queryset(default_manager)
iterable = cls.merge_querysets(default_queryset, iterable)
For reference, my implementation is as follows:
class PostType(DjangoObjectType):
class Meta:
model = Post
filter_fields = ['id', 'title']
interfaces = (graphene.relay.Node, )
class Query(graphene.ObjectType):
posts = DjangoFilterConnectionField(PostType)
def resolve_posts(self, info, **kwargs):
return Post.objects.prefetch_related('customer_posts').all()
Issue Analytics
- State:
- Created 5 years ago
- Reactions:2
- Comments:15 (2 by maintainers)
Top GitHub Comments
merge_queryset
is also impacting #758 & #787I don’t see an easy way to fix this. Maybe instead of trying to union querysets we pass through a single queryset.
We ended up overriding the method like this:
Now in your model you redefine the field and implement resolve.
So far it works, but I would love to know what am I breaking with this: