Specifying a different input type for a Pydantic model field (comma-separated string input as a list of strings)

huangapple go评论141阅读模式
英文:

Specifying a different input type for a Pydantic model field (comma-separated string input as a list of strings)

问题

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

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

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

我该如何修复这个问题?

import typing

from pydantic import BaseSettings, Field, validator


class Config(BaseSettings):
    systems: typing.List[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)

请注意,我已经将 systems 字段的类型提示更正为 typing.List[str],以反映其实际类型是字符串列表。

英文:

Using Pydantic, how can I specify an attribute that has an input type different from its actual type?

For example I have a systems field that contains a list of systems (so a list of strings) and the user can provide this systems list as a comma separated string (e.g. "system1,system2"); then I use a validator to split this string into a list of strings.

The code below is doing that and it's working but the type hinting is wrong as the systems field is actually a list of strings, not a string; the validator is splitting the original string into a list of strings.

How can I fix this?

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)

答案1

得分: 3

始终要使用您在模式中_实际需要的_类型来注释模型字段!

如果您希望字段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())

输出:

systems=['foo', 'bar']
systems=[]
systems=[]
英文:

Always annotate model fields with the types you actually want in your schema!

If you want the field systems to be a list of strings, then annotate it accordingly. A comma-separated string is the exception after all. To allow it, use a pre=True validator to intercept that string before the default field validators get to it (and raise an error). Then you can split it and return the list as you wish:

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())

Output:

systems=['foo', 'bar']
systems=[]
systems=[]

huangapple
  • 本文由 发表于 2023年5月25日 16:47:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76330421.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定