如何使用列表中的值作为 pydantic 验证器?

Posted

技术标签:

【中文标题】如何使用列表中的值作为 pydantic 验证器?【英文标题】:How to use values from list as pydantic validator? 【发布时间】:2021-04-04 12:18:58 【问题描述】:

我想创建 pydantic 模型来验证用户表单。 我的模型值之一应该从名称列表中验证。 我成功使用枚举创建模型如下:

from enum import Enum
class Fruit(str, Enum):
    APPLE = 'apple'
    BANANA = 'banana'
    MELON = 'melon'

from pydantic import BaseModel
class UserForm(BaseModel):
    fruit: Fruit
    name: str

现在我想将枚举切换到我的代码中的值列表:

fruit = ['apple','banana','melon']

我怎样才能做到这一点?

tnx

【问题讨论】:

【参考方案1】:

我提出了一个优雅的解决方案。

from pydantic import BaseModel
from typing import List
from enum import Enum


class Fruit(str, Enum):
    APPLE = 'apple'
    BANANA = 'banana'
    MELON = 'melon'


class UserForm(BaseModel):
    fruits: List[Fruit]
    name: str

就是这样。

您无需编写自己的验证器 告诉 pydantic 你需要一个 Fruit 对象的列表,它会为你做这件事

查看上面的代码:

把上面的代码放到一个文件main.py.

运行

python -i main.py
>>> uf = UserForm(fruits=['apple','banana'],name='hello')
>>> uf
UserForm(fruits=[<Fruit.APPLE: 'apple'>, <Fruit.BANANA: 'banana'>], name='hello')


>>> af = UserForm(fruits=['monkey','apple'],name='hello')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pydantic/main.py", line 400, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 1 validation error for UserForm
fruits -> 0
  value is not a valid enumeration member; permitted: 'apple', 'banana', 'melon' (type=type_error.enum; enum_values=[<Fruit.APPLE: 'apple'>, <Fruit.BANANA: 'banana'>, <Fruit.MELON: 'melon'>])
>>> 

pydantic 会引发错误,因为monkey 不在水果中。

【讨论】:

【参考方案2】:

您也可以通过Literal 类型的列表来执行此操作。像这样:

import pydantic
from typing import Literal, List

class M(pydantic.BaseModel):
    fruits: List[Literal["apple", "orange"]]

print(M.parse_obj("fruits":["apple", "orange"]))  # OK fruits=['apple', 'orange']
print(M.parse_obj("fruits":["apple", "orange", "potato"]))  # Error unexpected value potato

【讨论】:

【参考方案3】:

您可以通过以下方式使用validator

 from pydantic import BaseModel, ValidationError, validator
 class UserForm(BaseModel):
    fruit: str
    name: str
    @validator('fruit')
    def fruit_must_be_in_fruits(cls,fruit):
      fruits=['apple','banana','melon']
      if fruit not in fruits:
        raise ValueError(f'must be in fruits')
      return fruit
 try:
    UserForm(fruit="apple",name="apple")
 except ValidationError as e:
    print(e)

如果不符合条件会引发验证错误。

【讨论】:

嗨,非常感谢。但它仍然无法按我的意愿工作。我在 fastapi 中使用这个 UserForm,这意味着虽然 swagger/docs 会在我使用枚举解决方案时自动为用户建议所有值,但它不会在此解决方案中建议它们。【参考方案4】:

您可以通过其 .__members__ 字典获取有关枚举的信息 - 不过在这里您可以简单地迭代它的键:

from enum import Enum
class Fruit(str, Enum):
    APPLE = 'apple'
    BANANA = 'banana'
    MELON = 'melon'

# only need __members__ if you need more infos about it

print(Fruit.__members__)

# you do not need the __members__ if you just want the keys
print([name.lower() for name in Fruit])

输出:

# enums __members__ dictionary
'APPLE': <Fruit.APPLE: 'apple'>, 
 'BANANA': <Fruit.BANANA: 'banana'>, 
 'MELON': <Fruit.MELON: 'melon'> 

# lower keys
['apple', 'banana', 'melon']

【讨论】:

以上是关于如何使用列表中的值作为 pydantic 验证器?的主要内容,如果未能解决你的问题,请参考以下文章

pydantic学习与使用-7.字段顺序field-ordering

如何使用 Pydantic 解析模型列表

Python/Pydantic - 使用带有 json 对象的列表

如何给 Pydantic 列表字段一个默认值?

pydantic学习与使用-1.pydantic简介与基础入门

如何在 pydantic 模型中解析 ObjectId?