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