为何Pydantic模型验证器内__int/__str赋值不触发验证?
问题分析:Pydantic模型未触发预期验证的原因
问题代码
from pydantic import BaseModel, conint, constr, ValidationError, validator, Any, Optional 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
问题描述
执行p = IntOrStr(value=True)时,预期因True是布尔值无法通过__int和__str的验证,但实际__int = v和__str = v并未触发任何验证,原因如下:
核心原因
- 直接赋值不触发Pydantic字段验证:你在validator里写的
__int = v只是普通Python变量赋值,和模型定义的__int字段没有任何关联。Pydantic的字段校验逻辑只会在模型实例化、字段赋值(开启validate_assignment时)等框架触发的场景下运行,普通变量赋值不会调用这些校验规则。 - 字段与变量名混淆:模型里的
__int是私有字段,但你在validator里定义了同名局部变量,两者完全是不同的对象,局部变量的赋值操作根本不会触发表单字段的校验逻辑。
正确实现方式
要验证value是否符合__int或__str的规则,需要手动调用Pydantic的校验逻辑,比如用预定义的类型去校验值:
from pydantic import BaseModel, conint, constr, ValidationError, validator, Any class IntOrStr(BaseModel): # 把类型定义抽成类属性,避免和实例字段混淆 _int_validator = conint(strict=True, le=100, ge=10) _str_validator = constr(strict=True, max_length=64, min_length=10) value: Any @validator("value") def value_must_be_int_or_str(cls, v): # 用定义的校验器验证值 try: cls._int_validator(v) return v except ValidationError: pass try: cls._str_validator(v) return v except ValidationError: pass raise ValueError("error. value must be int or str") class Config: validate_assignment = True # 测试:此时传入True会触发验证失败 try: p = IntOrStr(value=True) except ValueError as e: print(e) # 输出:error. value must be int or str
补充说明
strict=True的作用是禁止自动类型转换(比如布尔值不能被当作整数),但必须通过Pydantic的校验入口触发才能生效。- 原代码中的
__int、__str私有字段属于冗余定义,因为你并没有实际使用它们来存储或校验值,抽成类属性的校验器更符合逻辑。
内容的提问来源于stack exchange,提问作者Kenny Davidson
相关产品推荐
相关产品推荐

