Search code examples
pythondjangographene-pythongraphene-django

Graphene and Django about relationships


I'm very new to Graphene and testing it to see if i could use it for a Django project with complex queries. To test it, i'm trying to create an Ecommerce with the following models

class Sku(models.Model):
    name = models.CharField(max_length=100)


class Product(models.Model):
    name = models.CharField(max_length=100)

class ProductSku(models.Model):
    sku = models.ForeignKey(Sku, related_name='product_sku', on_delete=models.CASCADE)
    product = models.ForeignKey(Product, related_name='product_sku', on_delete=models.CASCADE)
    price = models.IntegerField()

As you can see here Product and Sku have a many to many relationship using the model ProductSku

Using the documentation from Graphene i created the following Schema

class SkuNode(DjangoObjectType):
    class Meta:
        model = Sku


class ProductNode(DjangoObjectType):
    class Meta:
        model = Product

class ProductSkuNode(DjangoObjectType):     
    class Meta:
        model = ProductSku



class Query(graphene.ObjectType):
    all_products = graphene.List(ProductNode, name=graphene.String())

    product = graphene.Field(ProductNode, id=graphene.Int())

    def resolve_all_products(self, info, **args):
        name = args.get('name')
        if name is not None:
            return Product.objects.filter(name__icontains=name)
        return Product.objects.all()

    def resolve_product(self, info, **args):
        id = args.get('id')
        if id is not None:
            return Product.objects.filter(pk=id).first()

Right now my frontend app could get the price of a given product for a given sku by doing a query that asks for

query{
  allProducts{
    id,
    name,
    productSku{
      price,
      sku{
        id,
        name
      }
    }
  }
}

But what i want to do is a query that asks for the price inside the SkuNode

query{
  allProducts{
    id,
    name,
    sku{
      id,
      name,
      price
    }
  }
}

Is that posible?


Solution

  • You could add a sku field and resolver to ProductNode like:

    class ProductNode(DjangoObjectType):
        sku = graphene.Field(SkuNode)
    
        class Meta:
            model = Product
    
        def resolve_sku(self, info):
            return self.product_sku.sku # (however you get the Sku object from a Product instance)
    

    Then you'll have a sku field as part of the product response. But since what you're asking for is to mix fields from both the Sku and the ProductSku models, you are probably better off creating a new object type that is not a model type, it's just an ObjectType with 3 fields (id, name, price) and then dynamically returning an instance of that. So in that case you should do this for ProductNode

    class ProductNode(DjangoObjectType):
        sku = graphene.Field(SkuObjectType)
    
        class Meta:
            model = Product
    
        def resolve_sku(self, info):
            sku = self.product_sku.sku
            return SkuObjectType(id=sku.id, name=sku.name, price=self.product_sky.price)
    

    And you'd create the SkuObjectType like

    class SkuNode(DjangoObjectType):
        id = graphene.ID()
        name = graphene.String()
        price = graphene.Int()