如何将单个枚举用于 django 模型和 graphql 突变参数?

Posted

技术标签:

【中文标题】如何将单个枚举用于 django 模型和 graphql 突变参数?【英文标题】:How can I use a single enum for django model and graphql mutation arguments? 【发布时间】:2020-07-15 17:58:30 【问题描述】:

我已经定义了 Django 模型,其字段包含对应于枚举的文本选择。 GraphQL API 提供了带有 enum 类型参数的突变(不是直接从模型派生的),它应该只接受与模型相同的值。我怎样才能摆脱我的重复?

models.py

class SomeModel(models.Model):

    class SomeEnum(models.TextChoices):

        A = "A", _("Option A")
        B = "B", _("Option B")

    enum_field = models.CharField(
        max_length=1,
        choices=SomeEnum.choices,
        default=SomeEnum.A,
    )

schema.py


class SomeEnumSchema(graphene.Enum):

    A = "A"
    B = "B"


class SomeMutation(graphene.Mutation):

    class Arguments:
        some_enum = SomeEnumSchema(required=True)

【问题讨论】:

我不知道 python ... 将值提取到某个基类,两者都通用 - 多重继承? 【参考方案1】:

使用以下类扩展您的 graphene.Enum 实例

from inspect import getmembers, isroutine

class EnumChoices:
    @classmethod
    def choices(self):
        attributes = getmembers(self, lambda a: not (isroutine(a)))
        values = [(a[0], a[1]._value_) for a in attributes if hasattr(a[1], "_value_")]
        return values

您的示例枚举将如下所示

# import the EnumChoices class above 
from graphene import Enum

class YourExampleChoices(EnumChoices, Enum):
    BAD = "Bad"
    MEH = "Meh"
    NORMAL = "Normal"
    LIKE = "Like"
    LOVE = "Love"

您的示例 graphene.types.InputObjectType 将如下所示

# import the YourExampleChoices class above
from graphene.types import InputObjectType

class YourExampleChoicesMutationInput(InputObjectType):
    choice = YourExampleChoices(required=True)

您的示例 graphene.Mutation 将如下所示

# import the YourExampleChoicesMutationInput class above 
import graphene

from graphene.types.mutation import Mutation

class YourExampleMutation(Mutation):
    # make sure to define your mutation results fields

    class Arguments:
        input = YourExampleChoicesMutationInput(required=True)

    def mutate(root, info, input):
        # what do you want this mutation to do?
        pass

您的 Django 模型将如下所示

# import the YourExampleChoices class above
# notice that `YourExampleChoices.choices()` is callable, this is slightly different from the `Textchoices.choices` which isn't callable

class YourExampleModel(TimestampBase):
    choices = models.CharField(
        max_length=6, 
        choices=YourExampleChoices.choices(), 
        default=YourExampleChoices.NORMAL._value_
    )

【讨论】:

【参考方案2】:

如果您想在自定义突变中使用 Enums,您可以像这样使用graphine.Enum

class PermisionEnum(graphene.Enum):
    READ = "read"
    WRITE = "write"


class SimpleModelMutation(graphene.Mutation):

    class Arguments:
        # reusable
        permission = PermisionEnum(required=True)
        # not reusable
        scope = graphene.Enum('scope', [
            ("PERSONAL", "personal"),
            ("PROJECT", "project")
        ])(required=True)

我建议使用PermisionEnum(required=True) 方法,因为使用它PermisionEnum 类可以在不同的突变中重复使用。当您声明枚举时,这是不可能的,因为我使用 scope 归档!

【讨论】:

【参考方案3】:

您可以使用graphene.Enum.from_enum()

该函数可以将普通的Enum类型转换为graphene.Enum

请注意models.TextChoices 仅适用于 3.0 以上的 Dajango 版本

models.py(对于 Django 版本 >= 3.0)

from django.db import models

class SomeModel(models.Model):

    class SomeEnum(models.TextChoices):

        A = "A", _("Option A")
        B = "B", _("Option B")

    enum_field = models.CharField(
        max_length=1,
        choices=SomeEnum.choices,
        default=SomeEnum.A,
    )

models.py(适用于 Django 版本

from enum import Enum
class SomeEnum(Enum):
    A = "A"
    B = "B"

schema.py:

SomeEnumSchema = graphene.Enum.from_enum(SomeEnum)
class SomeMutation(graphene.Mutation):
    class Arguments:
        some_enum = SomeEnumSchema(required=True)

【讨论】:

对于 Django >= 3.0 版本的一个重要说明是每个枚举选项的类变量名称必须匹配元组的第一个元素。这意味着要使用 Option A 枚举的小写键,它必须写为 a = "a", _("Option A")

以上是关于如何将单个枚举用于 django 模型和 graphql 突变参数?的主要内容,如果未能解决你的问题,请参考以下文章

Django,当单个模型变大时模型拆分?

如何在 Django 中删除单个模型,并留下其他模型

如何在Django中基于枚举为模型字段设置默认值?

Django/Python:如何将整数转换为等效的枚举字符串? [复制]

Django/Python:如何将整数转换为等效的枚举字符串? [复制]

单个 Django 模型,多个表?