9

How to receive the native Model ID that stored in the DB (eg. django model ID) when we are executing the Relay query? The main issue that the Relay defines it's own ID so I'm not sure how can we correctly handle it.

For ex.

query {
  allFuelTypes (codeMatch: "g") {
    edges {
      node {
        id,
        code,
        label
      }
    }
  }
}

will print

{
  "data": {
    "allFuelTypes": {
      "edges": [
        {
          "node": {
            "id": "RnVlbFR5cGVOb2RlOjM=",
            "code": "g",
            "label": "Gas"
          }
        }
      ]
    }
  }
}

Where id is the Graphene Relay ID but I'd like to see the Model ID.

The only one possible way that I see is just to create some alias in the graphene Schema for the Model ID field and manually fetch this ID from the Django Model. But perhaps there is existing some more dynamic way to achieve the same result?

Thanks for any help!

P.S. the implementation of the query isn't important. It's just a dummy demo

Velidan
  • 5,526
  • 10
  • 48
  • 86

3 Answers3

16

This worked for me!

Let's define a simple model:

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

    class Meta:
        ordering = ['id']

Now let's define its corresponding Relay Node:

class AccountNode(DjangoObjectType):
    # just add this line
    id = graphene.ID(source='pk', required=True)

    class Meta:
        model = Account
        interfaces = (relay.Node, )

Attach it to you Query:

class Query(ObjectType):
    all_accounts = DjangoFilterConnectionField(AccountNode)

Make your request:

enter image description here

Juan-Kabbali
  • 1,961
  • 15
  • 20
6

You can define a custom field for pk, here is an example with user.

from django.contrib.auth import get_user_model
import graphene
from graphene_django.types import DjangoObjectType
from graphene_django.filter.fields import DjangoFilterConnectionField


class UserNode(DjangoObjectType):
    class Meta:
        model = get_user_model()
        interfaces = (graphene.relay.Node,)

    pk = graphene.Int()

    def resolve_pk(self, info):
        return self.pk

class UserQuery(graphene.ObjectType):
    user = graphene.relay.Node.Field(UserNode)
    users = DjangoFilterConnectionField(UserNode)

class Query(UserQuery, graphene.ObjectType):
    pass

schema = graphene.Schema(query=Query)

Then you can query like:

query {
  users{
    edges {
      node {
        pk
      }
    }
  }
}

You can check other examples here.

pedrobern
  • 1,134
  • 9
  • 24
  • Hi @pedrobern. Thank you for your answer. I mentioned this solution in my post, but, maybe, there is existing some elegant way how to receive the model id without aliasing this ID and manually resolving it? – Velidan Feb 03 '20 at 16:38
2

It can be easily resolved using a custom node. Like this -

class CustomNode(graphene.Node):
    """
    For fetching object id instead of Node id
    """

    class Meta:
        name = "Node"

    @staticmethod
    def to_global_id(type, id):
        return id

Now you just have to import it into your nodes Interfaces like -

class UserNode(DjangoObjectType):
    class Meta:
        model = get_user_model()
        interfaces = (CustomNode,)

Hope this serves your purpose.

Ameya Marathe
  • 141
  • 1
  • 3