pydantic 验证所有文字字段

问题描述 投票:0回答:1

我有多个 pydantic 2.x 模型,而不是对每个模型上的每个文字字段应用验证

class MyModel(BaseModel):
    name: str = ""
    description: Optional[str] = None
    sex: Literal["male", "female"]

    @field_validator("sex", mode="before")
    @classmethod
    def strip_sex(cls, v: Any, info: ValidationInfo):
        if isinstance(v, str):
            return v.strip()
        return v

我想使用与此类似的方法带注释的验证器

如何实现所有

Literal
字段的自动验证?

def strip_literals(v: Any) -> Any:
    if isinstance(v, str):
        return v.strip()
    return v

# doesn't work
# LiteralType = TypeVar("LiteralType", bound=Literal)
# LiteralStripped = Annotated[Literal, BeforeValidator(strip_literals)]

class MyModel(BaseModel):
    name: str = ""
    description: Optional[str] = None
    sex: LiteralStripped["male", "female"]

我想要类似上面的东西,但实际上无法在文字上定义正确的验证处理程序。

python python-typing pydantic literals
1个回答
0
投票

您必须将文字值的声明移动到注释中,如下所示:

from typing import Any, Optional, Annotated, TypeVar, Literal
from pydantic import BaseModel, BeforeValidator

def strip_literals(v: Any) -> Any:
    if isinstance(v, str):
        return v.strip()
    return v

LiteralStripped = Annotated[Literal["male", "female"], BeforeValidator(strip_literals)]

class MyModel(BaseModel):
    name: str = ""
    description: Optional[str] = None
    sex: LiteralStripped

m = MyModel(sex="foo")

哪个加注:

ValidationError                           Traceback (most recent call last)
Cell In[38], line 17
     14     description: Optional[str] = None
     15     sex: LiteralStripped
---> 17 m = MyModel(sex="foo")

File ~/software/mambaforge/envs/tysen-dev/lib/python3.11/site-packages/pydantic/main.py:164, in BaseModel.__init__(__pydantic_self__, **data)
    162 # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    163 __tracebackhide__ = True
--> 164 __pydantic_self__.__pydantic_validator__.validate_python(data, self_instance=__pydantic_self__)

ValidationError: 1 validation error for MyModel
sex
  Input should be 'male' or 'female' [type=literal_error, input_value='foo', input_type=str]
    For further information visit https://errors.pydantic.dev/2.5/v/literal_error

如果您想避免重复注释,您可以根据

__class_getiem__
定义一个别名:

from typing import Any, Optional, Annotated, TypeVar, Literal
from pydantic import BaseModel, BeforeValidator


class LiteralStripped:
    @staticmethod
    def strip_literals(v: Any) -> Any:
        if isinstance(v, str):
            return v.strip()
        return v

    def __class_getitem__(cls, values):

        return Annotated[Literal[values], BeforeValidator(cls.strip_literals)]

class MyModel(BaseModel):
    name: str = ""
    description: Optional[str] = None
    sex: LiteralStripped["male", "female"]

m = MyModel(sex="foo")

然而,这已经是一种高级模式,但它的工作原理与您的建议完全一样。

我希望这有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.