为 Pydantic 模型字段指定不同的输入类型(以逗号分隔的字符串输入作为字符串列表)

cyl*_*n86 4 python python-3.x pydantic

使用 Pydantic,如何指定输入类型与其实际类型不同的属性?

例如,我有一个systems包含系统列表(因此是字符串列表)的字段,用户可以将此系统列表作为逗号分隔的字符串提供(例如"system1,system2");然后我使用验证器将该字符串拆分为字符串列表。

下面的代码正在执行此操作并且它有效,但类型提示是错误的,因为系统字段实际上是字符串列表,而不是字符串;验证器将原始字符串拆分为字符串列表。

我怎样才能解决这个问题?

import typing

from pydantic import BaseSettings, Field, validator


class Config(BaseSettings):
    systems: str = Field([], description="list of systems as a comma separated list (e.g. 'sys1,sys2')")

    @validator("systems")
    def set_systems(cls, v) -> typing.List[str]:
        if v == "":
            return []
        systems = list(filter(None, v.split(",")))
        return systems


if __name__ == "__main__":
    c = Config(**{"systems": "foo,bar"})
    print(c)
Run Code Online (Sandbox Code Playgroud)

Dan*_*erg 5

始终使用您在架构中实际想要的类型来注释模型字段!

如果您希望该字段systems是字符串列表,请相应地对其进行注释。毕竟,以逗号分隔的字符串是例外。要允许它,请使用pre=True验证器在默认字段验证器到达该字符串之前拦截该字符串(并引发错误)。然后您可以拆分它并根据需要返回列表:

from pydantic import BaseSettings, Field, validator


class Config(BaseSettings):
    systems: list[str] = Field(default_factory=list)

    @validator("systems", pre=True)
    def split_comma_separated(cls, v: object) -> object:
        if isinstance(v, str):
            v = v.strip()
            return [] if v == "" else v.split(",")
        return v


if __name__ == "__main__":
    print(Config.parse_obj({"systems": "foo,bar"}))
    print(Config.parse_obj({"systems": ""}))
    print(Config())
Run Code Online (Sandbox Code Playgroud)

输出:

systems=['foo', 'bar']
systems=[]
systems=[]
Run Code Online (Sandbox Code Playgroud)