使用Strawberry Django,自动将Django的Choices转化为GraphQL的Enum

首先

在Strawberry Django中,创建一个添加了@strawberry.django.type装饰器的类将生成对应于Django的Model的Graphql类型。在此过程中,如果使用auto指定每个字段的类型,则会自动设置与Model定义相匹配的类型。
类型定义 – Strawberry Django

本文介绍了一个名为GENERATE_ENUMS_FROM_CHOICES的选项,它可以自动将使用Django的Model的choices的字段转换为GraphQL的Enum。

「Strawberry Django」是什么意思?

Strawberry是一个用Python编写的GraphQL库。
它的Django扩展是Strawberry Django。
(作为库名称为strawberry-graphql-django)

代码示例 (Code example)

行动确认版本

    • django: 3.2.19

 

    • strawberry-graphql: 0.194.1

 

    strawberry-graphql-django: 0.13.0

设置.py

STRAWBERRY_DJANGO = {
    "GENERATE_ENUMS_FROM_CHOICES": True,
}

models.py -> 模型.py .py)

在Task模型的priority字段上设置choices参数。

class Task(models.Model):
    PRIORITY_CHOICES = [
        ("L", "LOW"),
        ("M", "MEDIUM"),
        ("H", "HIGH"),
    ]
    title = models.CharField(max_length=200)
    priority = models.CharField(
        max_length=1,
        choices=PRIORITY_CHOICES,
        default="M",
    )

或者,还可以使用TextChoices来实现类似枚举的指定方式。

class PriorityChoices(models.TextChoices):
    LOW = "L", "LOW"
    MEDIUM = "M", "MEDIUM"
    HIGH = "H", "HIGH"

class Task(models.Model):
    title = models.CharField(max_length=200)
    priority = models.CharField(
        max_length=2,
        choices=PriorityChoices.choices,
        default=PriorityChoices.MEDIUM,
    )

模式.py

创建tasks查询。不创建自定义解析器处理,只是简单获取任务。

@strawberry_django.type(Task)
class TaskType:
    title: strawberry.auto
    priority: strawberry.auto


@strawberry.type
class Query:
    tasks: list[TaskType] = strawberry.django.field()


schema = strawberry.Schema(query=Query,)

被输出的模式

以下是自动生成的枚举选项。
在choices参数中传递的每个元组的第一个是值,第二个被视为字段的描述。

enum MyappTaskPriorityEnum {
  """Low"""
  L

  """Medium"""
  M

  """High"""
  H
}

type Query {
  tasks: [TaskType!]!
}

type TaskType {
  title: String!
  priority: MyappTaskPriorityEnum!
}
在本次代码示例中,我们对CharField指定了choices。
对IntegerField指定choices并使用auto进行转换时,并不会进行枚举转换,而只是变成了Int。
此外,在撰写时的最新版本0.14.0中,如果使用了IntegerChoices进行choices指定,会引发错误。
在引入具有使用IntegerField的字段的项目中,请注意这一点。
*我已经注意到这一点并提交了修正的PR。我认为在下一个发布版本之后,返回的Int将与使用元组进行指定的结果相同。
在文档中推荐在使用TextChoices和IntegerChoices时,使用django-choices-field库来定义模型字段,而不是使用GENERATE_ENUMS_FROM_CHOICES。考虑引入这个库可能是一个好选择。
然而,目前django-choices-field仍是个人的仓库,星数也较少,个人而言,对于将其正式投入生产环境还存在些许犹豫。

如果不使用GENERATE_ENUMS_FROM_CHOICES

順便提一下,如果不想使用此设置,想要在架构中使用Enum来表示choices,需要自己编写以下Enum类和其生成操作。 (根据项目可能会创建通用转换操作)

schema.py模块。

@strawberry.enum
class PriorityEnum(strawberry.Enum):
    LOW = 'L'
    MEDIUM = 'M'
    HIGH = 'H'

@strawberry.type
class TaskType:
    title: str
    description: str
    priority: PriorityEnum

def convert_task(task: Task) -> TaskType:
  """TaskTypeへの変換処理"""
    priority = task.priority
    if priority == PriorityChoices.LOW:
        converted_priority = PriorityEnum.LOW
    elif priority == PriorityChoices.MEDIUM:
        converted_priority = PriorityEnum.MEDIUM
    elif priority == PriorityChoices.HIGH:
        converted_priority = PriorityEnum.HIGH
    else:
        converted_priority = None

    return TaskType(
        title=task.title,
        description=task.description,
        priority=converted_priority,
    )
class Query:

    @strawberry.field
    def tasks(self, info) -> List[TaskType]:
        tasks = Task.objects.all()
        return [convert_task(task) for task in tasks]
广告
将在 10 秒后关闭
bannerAds