给定以下数据模型:
class Demo(BaseModel):
id: Union[int, str]
files: Union[str, List[str]]
有没有办法告诉pydantic
,当我访问它们时,总是自动将id
转换为str
类型,将files
转换为List[str]
类型,而不是每次都手动转换。
str
。默认情况下,默认字符串验证器只是将类型为int
、float
或Decimal
的值强制为str
。(参见str_validator
来源)
这意味着,即使将id
注释为str
,但传递了int
值,模型也将正确初始化而不会出现验证错误,并且id
值将是该值的str
版本。(例如str(42)
给出"42"
)
list
还内置了一个默认的验证器,但在这种情况下,它可能不是您想要的。如果它遇到一个非list
值,但看到它是一个序列(或生成器),它会再次将其强制为list
。(请参阅list_validator
来源)在这种情况下,由于您可能传递给它的值将是str
,而str
是一个序列,因此结果将是初始字符串中的单个字符串列表。(例如list("abc")
给出["a", "b", "c"]
)
因此,对于list[str]
,您可能需要自己的自定义pre=True
验证器来使用str
值执行您认为必要的任何操作,以将其转换为list[str]
。
示例:
from pydantic import BaseModel, validator
class Demo(BaseModel):
id: str
files: list[str]
@validator("files", pre=True)
def str_to_list_of_str(cls, v: object) -> object:
if isinstance(v, str):
return v.split(",")
return v
if __name__ == "__main__":
obj = Demo.parse_obj({"id": 42, "files": "foo,bar,baz"})
print(obj)
print(type(obj.id), type(obj.files))
输出:
id='42' files=['foo', 'bar', 'baz']
<class 'str'> <class 'list'>
正如您所看到的,如果您的值是int
,您甚至不需要任何额外的id
字段逻辑,因为它们在模型实例上最终为str
。
在得到维护人员的帮助后,我想出了如何制作它。关键是从类型定义中删除Union
,并在验证前使用预处理钩子转换值,以下是示例代码:
from pydantic import BaseModel, validator
from typing import List
class Demo(BaseModel):
id: str
files: List[str]
@validator('id', pre=True)
def id_must_be_str(cls, v):
if isinstance(v, int):
v = str(v)
return v
@validator('files', pre=True)
def files_must_be_list_of_str(cls, v):
if isinstance(v, str):
v = [v]
return v
obj = Demo.parse_obj({'id': 1, 'files': '/data/1.txt'})
print(type(obj.id))
print(type(obj.files))