Skip to content

DjangoConnectionField.resolve_connection replaces resolved queryset with clone, wiping query cache (causing N+1) #429

Closed
@richardpetithory

Description

@richardpetithory

I'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 QuerySets. 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()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions