Django&石墨烯:如何处理与polmorphic模型的双向关系?

时间:2018-03-29 18:06:07

标签: django graphene-python

我有一个看起来像这样的Django模型(当然简化):

from django.db import models
from polymorphic.models import PolymorphicModel

class Tournament(models.Model):
    slug = models.CharField(max_length=100, unique=True)

class Event(PolymorphicModel):
    tournament = models.ForeignKey(Tournament, related_name='events')
    slug = models.CharField(max_length=100)

class PracticeEvent(Event):
    pass

class MatchEvent(Event):
    winner = models.CharField(max_length=100, null=True, blank=True, default=None)

锦标赛由两类赛事组成:练习赛和比赛。我想使用Graphp使用Graphene公开这个模型。这就是我想出的:

import graphene
from graphene_django import DjangoObjectType

from . import models

class TournamentType(DjangoObjectType):
    class Meta:
        model = models.Tournament
        exclude_fields = ('id',)

class EventType(graphene.Interface):
    tournament = graphene.Field(TournamentType, required=True)
    slug = graphene.String(required=True)

class PracticeEventType(DjangoObjectType):
    class Meta:
        model = models.PracticeEvent
        interfaces = (EventType,)
        exclude_fields = ('id',)

class MatchEventType(DjangoObjectType):
    class Meta:
        model = models.MatchEvent
        interfaces = (EventType,)
        exclude_fields = ('id',)

extra_types = {PracticeEventType, MatchEventType}

class Query(graphene.ObjectType):
    tournaments = graphene.List(TournamentType)
    events = graphene.List(EventType)
    # ... resolvers ...

schema = graphene.Schema(
    query=Query,
    types=schema_joust.extra_types,)

到目前为止,这么好;我可以直接查询events { ... },甚至tournament也可用。但是,由于DjangoObjectType没有model = models.Event,我无法查询tournaments { events {...} } ...

我该如何解决这个问题?我无法EventType DjangoObjectTpe,我不知道在事后添加events字段。

2 个答案:

答案 0 :(得分:3)

他们自己EventType.tournamentTournamentType.events并不那么难。第一个显示在问题中,第二个可以像这样实现:

class EventType(graphene.Interface):
    slug = graphene.String(required=True)

class TournamentType(DjangoObjectType):
    class Meta:
        model = models.Tournament
        exclude_fields = ('id',)

    events = graphene.List(EventType)

    def resolve_events(self, info):
        return self.events.all()

graphene-django无法识别这种关系,但手动声明和解析该字段可以解决问题。为了获得反向场,如果我们不需要引用TournamentType那就可以工作,我挖掘石墨烯 - django并找到graphene_django.converter.convert_django_field_with_choices。这让我们可以像这样定义字段:

import graphene
from graphene_django import DjangoObjectType, converter, registry

from . import models

class EventType(graphene.Interface):
    tournament = converter.convert_django_field_with_choices(
        models.Event.tournament.field, registry.get_global_registry())
    slug = graphene.String(required=True)

答案 1 :(得分:0)

也许你想要Union类型,并明确声明EventType从接口继承:

import graphene

# Rename your existing EventType to EventTypeInterface and redefine like 
class EventType(DjangoObjectType):
    class Meta:
        model = Event
        interfaces = [EventTypeInterface]


class EventUnionType(graphene.Union):
    @classmethod
    def resolve_type(cls, instance, info):
        if isinstance(instance, MatchEvent):
            return MatchEventType
        elif isinstance(instance, PracticeEvent):
            return PracticeEventType
        return EventType

    class Meta:
        types = [MatchEventType, PracticeEventType, EventType]