Skip to content

Model inheritance in combination with graphene.Union and DjangoOrderedFilterConnection #1299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
piccarsso opened this issue Feb 9, 2022 · 3 comments

Comments

@piccarsso
Copy link

For a project I need to retrieve a list of videos from a database, which can be of different types. I need the possibility of filtering and pagination. The model uses inheritance (in this case with django_model_utils and InheritanceManager). So I have a BaseLearnVideo and derived from it e.g. MusicLearnVideo, DrawingLearnVideo.

For example, if I have the following models:

    class BaseLearnVideo():
      objects = InheritanceManager()
      title = models.CharField('Title, max_length=200, blank=False)
    
    class MusicLearnVideo(BaseLearnVideo)
      something_special = models.CharField('Something special', max_length=200, blank=False)
    
    class DrawingLearnVideo(BaseLearnVideo)
      cover_image = models.ImageField('Cover image')

I would like to query all learning videos as a list, a mixed list of the types MusicLearnVideo and DrawingLearnVideo. Therefore, graphene.Union would fit.

So in my schema I have:

    class MusicLearnVideoType(DjangoObjectType):
        class Meta:
            model = MusicLearnVideo
            fields = ('id', 'something_special')
            interfaces = (gql.Node,)
    
    class DrawingLearnVideoType(DjangoObjectType):
        class Meta:
            model = DrawingLearnVideo
            fields = ('id', 'cover_image')
            interfaces = (gql.Node,)
    
    class AllLearnVideosUnion(graphene.Union):
        class Meta:
            types = (MusicLearnVideoType, DrawingLearnVideoType)

  class AllLearnVideosConnection(graphene.Connection):
    class Meta:
        node = AllLearnVideosUnion

It works with graphene.Connection:

    all_learn_videos = graphene.ConnectionField(AllLearnVideosConnection)

    def resolve_all_learn_videos(self, info, **kwargs):
        return BaseLearnVideo.objects.all().select_subclasses()

As there can be a lot of different videos, I don't want to query them all, but have a pagination and filters. What I'd like to make is something like:

    all_learn_videos = DjangoFilterConnectionField(AllLearnVideosUnion)

    def resolve_all_learn_videos(self, info, **kwargs):
        return BaseLearnVideo.objects.all().select_subclasses()

The query:

    {
    edges {
      node {
        __typename
        ... on MusicLearnVideoType {
          id
          somethingSpecial
        }
        ... on DrawingLearnVideoType {
          id
         coverImage
        }
      }
    }
  }

I thought of resolving the queryset beforehand, and addressing the filters and pagination in the resolve function of the query, but as there already is the DjangoFilterConnectionField it would be nice to use that :-) I am not sure if this is even possible from a technical point of view, as I have not gone deep into the code of graphene-django.

Thanks a lot in advance for your thoughts on that!

@piccarsso
Copy link
Author

I found that the derived classes will be available in the query of the base class, so one could simply just query the base class and then access the child classes, like:

{
    edges {
      node {
        id
        musiclearnvideo {
          somethingSpecial
       }
       drawinglearnvideo {
         coverImage
      }
      }
    }
  }

I think this solves my problem.

@DrumsnChocolate
Copy link

DrumsnChocolate commented Apr 1, 2022

Hi! I just encountered a similar problem, where I am trying to merge two querysets from different models, but still want to be able to use the filtering and pagination functionality from DjangoFilterConnectionField.
I think it would work for my case to define a superclass for the two models, but I'm curious as to how you defined the superclass in the end; did your BaseLearnVideo extend django's Model?

@pfcodes
Copy link

pfcodes commented Jul 8, 2023

Using DjangoFilterConnectionField with Unions and Interfaces is much needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants