1

我有 4 种类型的配置文件。有些领域是相同的,有些是不同的。每个配置文件都有自己的 url,所以我使用 ContentType 作为映射 urls<->profiles 的中心位置。

# profiles/models.py
class Sport(models.Model):
    pass

class ProfileAbstract(models.Model):
    pass

class ProfileOrganization(ProfileAbstract):
    pass

class ProfilePlace(ProfileAbstract):
    pass

class ProfileTeam(ProfileAbstract):
    pass

class ProfileUser(ProfileAbstract):
    pass

class ProfileURL(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    slug = models.SlugField(max_length=30)  # Url

    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.CharField(max_length=36)  # CharField because I use UUID
    content_object = GenericForeignKey('content_type', 'object_id')

PS 直接查找的示例可以在这个 github 问题中找到。

4

1 回答 1

0
# profiles/schema.py
import graphene

from graphene_django.types import DjangoObjectType

from .models import (ProfileOrganization, ProfilePlace, ProfileTeam, ProfileUser,ProfileURL, Sport)

# [ START: Types ]
class SportType(DjangoObjectType):
    class Meta:
        model = Sport


class ProfileURLType(DjangoObjectType):
    class Meta:
        model = ProfileURL

    slug = graphene.String()
    model_name = graphene.String()

    def resolve_slug(self, info):
        return self.slug

    def resolve_model_name(self, info):
        return self.content_object.__class__.__name__  # ex. 'ProfileTeam'


class ProfileOrganizationType(DjangoObjectType):
    """
    Use this class as a basic class for other Profile Types classes
    """

    class Meta:
        model = ProfileOrganization
        fields = ('name', 'logo_data', 'profile_url')

    profile_url = graphene.Field(ProfileURLType)

    def resolve_profile_url(self, args):
        return self.profile_url.first()


class ProfilePlaceType(ProfileOrganizationType):
    class Meta:
        model = ProfilePlace


class ProfileTeamType(ProfileOrganizationType):
    class Meta:
        model = ProfileTeam


class ProfileUserType(ProfileOrganizationType):
    class Meta:
        model = ProfileUser


class ProfileTypeUnion(graphene.Union):
    class Meta:
        types = (ProfileOrganizationType, ProfileTeamType, ProfilePlaceType, ProfileUserType)
# [ END: Types ]


# [ START: Queries ]
class Query(graphene.ObjectType):
    """
    EXAMPLE OF QUERY:

    query profileDetails {
      profileDetails(profileUrl: "8auB-pMH-6Sh") {
        ... on ProfileTeamType {
          id,
          name,
          skillLevel,
          sport {
            name
          },
          profileUrl {
            slug,
            modelName
          }
        }

        ... on ProfilePlaceType {
          id,
          name,
          sports {
            name
          },
          profileUrl {
            slug,
            modelName
          }
        }
      }
    }
    """

    profile_details = graphene.Field(ProfileTypeUnion, required=True, profile_url=graphene.String())

    def resolve_profile_details(self, info, profile_url):
        profile_url_type = ContentType.objects.get(app_label='profiles', model='profileurl')
        profile_url_inst = profile_url_type.get_object_for_this_type(slug=profile_url)

        return profile_url_inst.content_object
# [ END: Queries ]

... on ProfileTeamType是内联片段(详细信息)。如您所见,我们在上面的示例中查询了 2 个片段(但是在我的情况下,根据配置文件类型的数量,它应该是 4 个),但是只有一个片段/模型返回数据 - 引用profileUrl了询问。


从前端根据收到的信息,modelName我们可以根据需要处理字段。

此外,上面提到的片段 > 1 的查询会在浏览器的控制台中引发 2 个错误(我在前端使用 Apollo 客户端):

  1. 您正在使用简单(启发式)片段匹配器,但您的查询包含联合或接口类型。Apollo Client 将无法准确映射片段。要消除此错误,请 IntrospectionFragmentMatcher按照文档中的说明使用: https ://www.apollographql.com/docs/react/advanced/fragments.html#fragment-matcher

(错误链接不正确。正确的是这个。)

  1. 警告:启发式片段匹配正在进行!

看来这是一个错误(github问题)。

为了修复它,我们需要在 Apollo 设置中添加缓存选项,它应该如下所示:

import ApolloClient from 'apollo-client';
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http';

const fragmentMatcher = new IntrospectionFragmentMatcher({
  introspectionQueryResultData: {
    __schema: {
      types: []
    }
  }
})

const cache = new InMemoryCache({ fragmentMatcher });

const client = new ApolloClient({
  cache,
  link: new HttpLink(),
});
于 2019-11-14T14:38:00.717 回答