如何在Pydantic 2中对each_item应用验证器?

1 投票
1 回答
65 浏览
提问于 2025-04-14 17:24

我正在把一个微服务从 Pydantic 1 迁移到 Pydantic 2。之前我有这样的代码:

class ComplementQuery(BaseModel):
    imports: List[str] = Field(default_factory=list)
    subquery: str = Field(...)

    @validator("imports", pre=True, each_item=True)
    def complement_imports(cls, value: str) -> str:
        return f'import "{value}"'

我看了文档,发现现在必须使用 @field_validator。要把原来的验证器替换掉,并把 "pre=True" 改成 "mode='Before'"。不过对于 each_item 我不太确定该怎么处理。现在我有这样的代码:

class ComplementQuery(BaseModel):
    imports: List[Annotated[str, Field(default_factory=List)]]
    subquery: str = Field(...)

    @field_validator("imports", mode="before")
    @classmethod
    def complement_imports(cls, value: str) -> str:
        return f'import "{value}"'

那么 complement_imports 这个验证器会应用到每一个 imports 项目上吗?还是说我应该把 pydantic.functional_validators 的 BeforeValidator 放在 Field 里?我有点困惑。

也许应该像这样:

def complement_imports(v: str) -> str:
    return f'import "{v}"'


class ComplementQuery(BaseModel):
    imports: List[
        Annotated[str, BeforeValidator(complement_imports), Field(default_factory=List)]
    ]
    subquery: str = Field(...)

1 个回答

0

我觉得正确的定义是这样的:

from pydantic import BaseModel, Field, BeforeValidator
from typing import Annotated, List

def complement_imports(v: str) -> str:
    return f'import "{v}"'


ImportItem = Annotated[str, BeforeValidator(complement_imports)]

class ComplementQuery(BaseModel):
    imports: List[ImportItem] = Field(default_factory=list)
    subquery: str = Field(...)

print(ComplementQuery(imports=["a", "b"], subquery="c"))
print(ComplementQuery(subquery="c"))

这段代码会输出:

imports=['import "a"', 'import "b"'] subquery='c'
imports=[] subquery='c'

通过定义 ImportItem 这个别名,你可以更方便地重复使用。默认工厂是应用在 imports 这个字段上,而不是应用在你例子中的那个项目上。

希望这对你有帮助!

撰写回答