0

This is specifically for graphene-django (not just graphene) when performing a node(id: ...) {} query.

Assume a fixed schema with 2 (or more) different GraphQL object types using graphene_django.DjangoObjectType linked to the same django model:

import graphene_django
from .models import Org as OrgModel

class Org(graphene_django.DjangoObjectType):
    class Meta:
        model = OrgModel
        fields = (
            "id",
            "name",
            "billing"
        )

class AnonymousOrg(graphene_django.DjangoObjectType):
    class Meta:
        model = OrgModel
        fields = (
            "id",
            "name",
        )

Let's assume a query to Org of ID 7eca71ed-ff04-4473-9fd1-0a587705f885.

btoa('Org:7eca71ed-ff04-4473-9fd1-0a587705f885')
'T3JnOjdlY2E3MWVkLWZmMDQtNDQ3My05ZmQxLTBhNTg3NzA1Zjg4NQ=='
{
  node(id: "T3JnOjdlY2E3MWVkLWZmMDQtNDQ3My05ZmQxLTBhNTg3NzA1Zjg4NQ==") {
    id
    __typename
    ... on Org {
      id
    }
  }
}

Return:

{
  "data": {
    "node": {
      "id": "QW5vbnltb3VzT3JnOjdlY2E3MWVkLWZmMDQtNDQ3My05ZmQxLTBhNTg3NzA1Zjg4NQ==",
      "__typename": "AnonymousOrg"
    }
  }
}

It returns the other object type 'AnonymousOrg:7eca71ed-ff04-4473-9fd1-0a587705f885', despite the relay ID specifying it was an Org object.

Is there a way in graphene-django to "hint" or provide detail to assure the return type if what's specified in the ID and its fragment?

Clarification on question

Other questions were discussing graphene, not specifically graphene-django, which is doing the type determinations in this case.

This is different from Django-graphene multiple types for the same model, as that one asked about how to handle field permissions and opened possibility to reconsidering schema structure (e.g. splitting between Public and Private API schemas) - that isn't a choice in this question.

Credit: This is graphene django models are based on the ones from the question at Django-graphene multiple types for the same model.

P.S. I created a bug issue on the tracker here: graphene-django#1291 named "DjangoObjectType using the same django model do not resolve to correct relay object". Supposedly this issue was resolved years ago, but communication lines got crossed.

tony
  • 870
  • 7
  • 16

2 Answers2

0

The credit to this goes to @Boolangery (GitHub)'s workaround on May 25th, 2020.

class FixRelayNodeResolutionMixin:
    @classmethod
    def get_node(cls, info, pk):
        instance = super(FixRelayNodeResolutionMixin, cls).get_node( info, pk)
        setattr(instance, "graphql_type", cls.__name__)
        return instance

    @classmethod
    def is_type_of(cls, root, info):
        if hasattr(root, "graphql_type"):
            return getattr(root, "graphql_type") == cls.__name__
        return super(FixRelayNodeResolutionMixin, cls).is_type_of(root, info)

Usage, here is an example with a django User model with two Django Graphene objects pointing to it: PublicUserType and UserType:

from graphene_django import DjangoObjectType


class PublicUserType(FixRelayNodeResolutionMixin, DjangoObjectType):
    class Meta:
        model = User
        interfaces = (graphene.relay.Node,)
        fields = ['id', 'first_name', 'last_name']

class UserType(FixRelayNodeResolutionMixin, DjangoObjectType):
    class Meta:
        model = User
        interfaces = (graphene.relay.Node,)
        fields = ['id', 'first_name', 'last_name', 'profile']
tony
  • 870
  • 7
  • 16
  • The credit for above goes to [this post](https://github.com/graphql-python/graphene-django/issues/971#issuecomment-633507631) on GitHub on May 25th, 2020. For now I've made this into a wiki. – tony Jul 10 '22 at 13:07
0

today I was the same issue and I solved it as stackoverflow

For me works reorder the classes types from class type with less fields to class type with more fields.

So,

class AnonymousOrg(graphene_django.DjangoObjectType):
    class Meta:
        model = OrgModel
        fields = (
            "id",
            "name",
        )

class LiteOrg(graphene_django.DjangoObjectType):
    class Meta:
        model = OrgModel
        fields = (
            "id",
            "name",
            "billing"
        )

class OrgAll(graphene_django.DjangoObjectType):
        class Meta:
            model = OrgModel
            fields = '__all__'