如何在Pydantic抽象模型中用私有字段验证公共字段?
Pydantic中用私有字段+抽象方法实现字段验证的方案
这个需求完全可以实现,但你当前的代码存在逻辑顺序问题,导致验证器拿不到_nai_pattern的值——因为Pydantic的字段验证是在实例初始化(__init__)之前执行的,等check_nai_format跑起来的时候,_nai_pattern还没被赋值,而且因为是私有字段,也不会出现在验证器的values参数里。
问题出在哪
- 验证时机不对:
@validator是类级别的逻辑,执行时间早于__init__,实例还没创建,你在__init__里给_nai_pattern赋值的代码根本还没运行。 - 私有字段不进验证上下文:就算你提前设置了
_nai_pattern,underscore_attrs_are_private = True会让Pydantic把它当成私有属性,不会把它放到验证器的values字典里供你调用。
修正后的实现方案
我们可以把set_nai_pattern改成抽象类方法,让验证器直接调用子类的类方法获取预期的NAI格式,同时保留私有字段存这个值(如果需要的话)。
Pydantic v1 版本代码
from abc import ABC, abstractmethod from pydantic import BaseModel, validator class BaseAsset(BaseModel, ABC): amount: int precision: int nai: str _nai_pattern: str = None @classmethod @abstractmethod def set_nai_pattern(cls) -> str: pass @validator('nai') def check_nai_format(cls, v): expected_pattern = cls.set_nai_pattern() if v != expected_pattern: raise ValueError(f"NAI格式错误,必须是{expected_pattern}") return v def __init__(self, **kwargs): super().__init__(**kwargs) # 实例化后把模式存入私有字段 object.__setattr__(self, '_nai_pattern', self.set_nai_pattern()) class Config: underscore_attrs_are_private = True class AssetHive(BaseAsset): @classmethod def set_nai_pattern(cls): return "@@000000021"
Pydantic v2 版本代码
如果用v2的话,推荐用@field_validator替代旧的@validator,还可以用model_post_init替代手动重写__init__:
from abc import ABC, abstractmethod from pydantic import BaseModel, field_validator class BaseAsset(BaseModel, ABC): amount: int precision: int nai: str _nai_pattern: str = None @classmethod @abstractmethod def set_nai_pattern(cls) -> str: pass @field_validator('nai') def check_nai_format(cls, v): expected_pattern = cls.set_nai_pattern() if v != expected_pattern: raise ValueError(f"NAI格式错误,必须是{expected_pattern}") return v def model_post_init(self, __context): self._nai_pattern = self.set_nai_pattern() class Config: underscore_attrs_are_private = True class AssetHive(BaseAsset): @classmethod def set_nai_pattern(cls): return "@@000000021"
核心调整点
- 把
set_nai_pattern改成抽象类方法:验证器本身是类方法,这样就能直接调用cls.set_nai_pattern()拿到子类定义的格式,不用依赖实例属性。 - 私有字段
_nai_pattern仅用于实例化后存值:如果不需要在实例里保留这个模式,直接删掉私有字段,验证器里直接调用类方法就行。 - 验证逻辑和子类绑定:每个子类的NAI格式验证会自动用自己定义的模式,符合抽象类的设计初衷。
内容的提问来源于stack exchange,提问作者Jakub_Z
相关产品推荐
相关产品推荐

