Pydantic:在将值分配给字段之前转换值?

Pydantic: Transform a value before it is assigned to a field?

我有以下型号

class Window(BaseModel):
    size: tuple[int, int]

我想像这样实例化它:

fields = {'size': '1920x1080'}
window = Window(**fields)

当然这会失败,因为 'size' 的值类型不正确。但是,我想添加逻辑以便将值拆分为 x,即:

def transform(raw: str) -> tuple[int, int]:
    x, y = raw.split('x')
    return int(x), int(y)

Pydantic 支持这个吗?

您可以使用 pydantic 的 validator 实现这样的行为。给定您的预定义函数:

def transform(raw: str) -> tuple[int, int]:
    x, y = raw.split('x')
    return int(x), int(y)

您可以像这样在 class 中实现它:

from pydantic import BaseModel, validator


class Window(BaseModel):
    
    size: tuple[int, int]
    _extract_size = validator('size', pre=True, allow_reuse=True)(transform)

注意传递给验证器的 pre=True 参数。这意味着它将 运行 before 默认验证器检查 size 是否是一个元组。

现在:

fields = {'size': '1920x1080'}
window = Window(**fields)
print(window)
# output: size=(1920, 1080)

请注意,在那之后,您将无法使用大小元组实例化 Window

fields2 = {'size': (800, 600)}
window2 = Window(**fields2)
# AttributeError: 'tuple' object has no attribute 'split'

为了克服这个问题,如果元组被传递,您可以通过稍微改变您的代码来简单地绕过该函数:

def transform(raw: str) -> tuple[int, int]:
    if type(raw) == tuple:
        return raw
    x, y = raw.split('x')
    return int(x), int(y)

哪个应该给出:

fields2 = {'size': (800, 600)}
window2 = Window(**fields2)
print(window2)
# output: size:(800, 600)