我已经定义了pydantic模型。当我运行p = IntOrStr(value=True)
时,我预期会失败,因为True
是布尔值,它应该会失败对__int
和__str
的赋值
class IntOrStr(BaseModel):
__int: Optional[conint(strict=True, le=100, ge=10)] = None
__str: Optional[constr(strict=True, max_length=64, min_length=10)] = None
value: Any
@validator("value")
def value_must_be_int_or_str(cls, v):
try:
__int = v # no validation. not sure why?
return v
except ValidationError as e:
print(str(e))
try:
__str = v # no validation. not sure why?
return v
except ValidationError as e:
print(str(e))
raise ValueError("error. value must be int or str")
class Config:
validate_assignment = True
有人知道为什么__int = v
和__str = v
不触发任何验证吗?
谢谢。
1条答案
按热度按时间s4n0splo1#
这里有不少问题。
命名空间
这与Pydantic无关;这只是对Python名称空间工作方式的误解:
在方法的命名空间中,
__int
和__str
只是局部变量,您所做的只是创建这些变量并为它们赋值,然后丢弃它们而不对它们做任何操作。它们与模型的字段/属性完全无关。
如果要为类属性赋值,则必须执行以下操作:
但这不是你想要的因为...
类与示例
验证器是一个类方法,这是由第一个名为
cls
的参数所暗示的,即使@classmethod
装饰器可以在@validator
中省略。因此,无论
validate_assignment
的配置如何,你都无法在验证器中为模型示例的任何字段 * 赋值 *,验证器只是 * 处理 * 提供给示例赋值的值,如果没有其他验证器的阻碍,它返回的值 * 可能 * 最终被赋值给示例。如果希望传递给一个字段的值影响最终分配给 * other * 字段的值,则应该使用
@root_validator
。验证器优先级
你需要考虑验证器被调用的顺序。这个顺序是由定义 * 字段 * 的顺序决定的。(参见docs)
默认情况下根验证器在字段验证器之后被称为 * after * field validators,因此,如果你想让根验证器所做的更改影响字段验证,你需要在它上面使用
pre=True
。下划线
Pydantic不将名称以下划线开头的属性视为字段,这意味着它们不受验证的约束。如果需要以下划线开头的字段名,则必须使用别名。
工作示例
总的来说,我猜您需要的东西更像是:
输出:
注意,在这个设置中,错误实际上是由
conint
和constr
类型的 * 单独 * 默认字段验证器拾取的。另外,在这个简单的例子中,您不能手动设置
__a
或__b
,因为这些值总是在根验证器中被覆盖,但是由于我不知道您的实际意图,我只是这样设置它来触发您想要的验证错误。希望这个有用。