Pydantic:将默认字段定义为另一个字段的函数

0 投票
1 回答
51 浏览
提问于 2025-04-14 17:59

我正在使用pydantic的数据类来创建一个不可变的数据类,这个数据类包含一个 name(名字)、一个 label(标签)和一个 id(标识符)。我希望在创建 MyClass 对象时,可以指定标签,或者根据 name 的值来给一个默认的标签。

目前的实现方式只有在 label 是输入参数的一部分时才有效,代码如下:

@dataclass(frozen=True)
class MyClass
    name: str = Field(default="class_name")
    label: str = Field(default=None)
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))

    _validate_uuid = field_validator("id")(uuid_error)

    @field_validator("label")
    def set_default_label(cls, v, values):
        if v is None:
            v = foo(values["name"])
        return v
    ...

使用这段代码,我们可以触发两种不同的行为:

MyClass(name="object_name", label=None)

返回的对象是 正确的MyClass(name="object_name", label=foo("object_name"),...)

但是如果我们依赖于 label 的默认值,比如使用下面的代码:

MyClass(name="object_name")

那么验证器就不会被调用,label 会保持为 None

MyClass(name="object_name", label=None)

1 个回答

1

在Pydantic中,如果不做额外的设置,默认值是不会被验证的。所以你需要在定义数据类的时候,传入相应的配置选项。看看下面这个例子:

from pydantic import Field, field_validator, ConfigDict
import uuid
from pydantic.dataclasses import dataclass

def foo(name):
    return name + "_label"


@dataclass(config=ConfigDict(validate_default=True))
class MyClass:
    name: str = Field(default="class_name")
    label: str = Field(default=None)
    id: str = Field(default_factory=lambda: str(uuid.uuid4()))

    @field_validator("label", mode="before")
    @classmethod
    def set_default_label(cls, v, info):
        if v is None:
            v = foo(info.data["name"])
        return v

print(MyClass())

这个例子会输出:

MyClass(name='class_name', label='class_name_label', id='fda6cbe7-a756-4e93-9924-0cd024f59251')

另外,我觉得明确说明验证模式是个好主意,并且把验证声明为一个类方法。

希望这对你有帮助!

撰写回答