Search code examples
pythondjangographqlgraphene-python

Django multi-table inheritance and graphene


I am trying to serve a graphql endpoint through django-graphene. I have the following models:

class BaseModel(models.Model):
    fk = models.ForeignKey(MainModel, related_name='bases')
    base_info = models.CharField(...)

class ChildModel(BaseModel):
    name = models.CharField(...)

MainModel being my central data model. There are several variants of ChildModel, which explains the multi-table inheritance used here. I have been able to get things to work with this schema declaration:

class BaseModelType(DjangoObjectType):
    class Meta:
        model = BaseModel

class ChildModelType(DjangoObjectType):
    class Meta:
        model = ChildModel

class MainModelType(DjangoObjectType):
    class Meta:
        model = MainModel

which allows the following graphQL query:

{
  mainModel(id: 123) {
    id
    bases {
      id
      baseInfo
      childmodel {
        id
        name
      }
    }
  }
}

However, I'd like to flatten this the way Django understands the inheritance, so that I can query the data like this:

{
  mainModel(id: 123) {
    id
    bases {
      id
      baseInfo
      name        <--- this field from the child is now on the base level
    }
  }
}

I suspect the answer is in how I declare ChildModelType, but I haven't been able to figure it out. Any hints appreciated!


Solution

  • You can do it by declaring additional field and resolve method in BaseModelType class:

    class BaseModelType(DjangoObjectType):
        name_from_child = graphene.String()
    
        class Meta:
            model = BaseModel
    
        def resolve_name_from_child(self, info):
            # if ChildModel have ForeignKey to BaseModel
            # first_child = self.childmodel_set.first()
    
            # for your case with multi-table inheritance
            # ChildModel is derived from BaseModel: class ChildModel(BaseModel):
            first_child = self.childmodel
    
            if first_child:
                return first_child.name
            return None
    

    query:

    {
      mainModel(id: 123) {
        id
        bases {
          id
          baseInfo
          name_from_child   <--- first child name
        }
      }
    }