石墨烯-django与ManyToMany和贯穿表

时间:2019-04-27 13:11:32

标签: django graphql graphene-python

我的应用具有以下几种通过模型的多对多关系:

class Person(models.Model):
    name = models.CharField()

class Group(models.Model):
    name = models.CharField()
    members = models.ManyToManyField(Person, through='Membership')

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()  # Extra info on the relationship

在没有成员资格中间类型(选项A)的graphql中表示此数据似乎很直观:

{
  "data": {
    "persons": [
      {
        "id": "1",
        "name": "Jack",
        "groups": [
          {
            "id": 3,                     # From Group-model
            "name": "Students",          # From Group-model
            "date_joined": "2019-01-01"  # From Membership-model
          },
          ...
        ]
      }
    ]
  }
}

vs。选项B:

{
  "data": {
    "persons": [
      {
        "id": "1",
        "name": "Jack",
        "memberships": [
          {
            "id": 9,
            "date_joined": "2019-01-01"
            "group": {
              "id": 3, 
              "name": "Students"
            }
          },
          ...
        ]
      }
    ]
  }
}

我找不到有关如何使用(django-)石墨烯实现选项A的任何示例。如何做到这一点,是否可以立即使用?

两种方法的优缺点是什么?数据也需要经常更改,这会改变判决吗?

1 个答案:

答案 0 :(得分:0)

您可以通过创建一个表示两个模型中字段的类型来实现此目的。例如:

import graphene
from graphene_django.types import DjangoObjectType


# hybrid type, expresses some characteristics of Member and Group
class UserGroupType(DjangoObjectType):
    class Meta:
        model = Membership
    
        # date_joined is automatically derived from the membership
        # instance, name and id are declared below.
        fields = ('id', 'name', 'date_joined', )
    
    id = graphene.ID()
    name = graphene.String()
    
    def resolve_id(value_obj, info):
        return value_obj.group.pk

    def resolve_name(value_obj, info):
        return value_obj.group.name


class PersonType(DjangoObjectType):
    class Meta:
        model = Person
    
        # id and name are automatically derived from the person
        # instance, groups is declared below, overriding the 
        # normal model relationship.
        fields = ('id', 'name', 'groups', )
    
    groups = graphene.List(UserGroupType)
    
    def resolve_groups(value_obj, info):
        return value_obj.memberships

对于从石墨烯的ObjectTypeDjangoObjectType descends from)构建的任何类型,要在输出中表示字段,您需要做两件事:

  1. 字段type的声明
  2. 解析器方法,该方法生成要转换为该类型的结果

DjangoObjectType评估您提供的模型以自动生成这些模型,并使用fields attribute来定制要显示的属性。

通过自定义fields,然后为要添加的内容添加手动道具/解析器,可以使类型返回您想要的任何内容。

请注意,解析器不会收到self作为第一个参数,而是会收到value object。值对象是查询解析器的返回值,通常是模型的实例或与过滤器匹配的模型数组等。