如何基于父模型protocol字段实现Pydantic Union鉴别器?
Pydantic实现跨字段关联的模型反序列化
完全可以实现这种需求,核心是用自定义模型验证器,在反序列化时根据protocol字段的值,动态把protocol_params解析成对应的模型。下面是针对多协议场景的具体实现:
1. 定义各协议参数模型
先把所有协议对应的参数模型写好,后续新增协议直接扩展即可:
from pydantic import BaseModel, ValidationError, model_validator from typing import Union, Dict, Any class ProtocolOneParam(BaseModel): param_a: str param_b: int class ProtocolTwoParam(BaseModel): param_c: float param_d: bool # 示例新增协议参数模型 class ProtocolThreeParam(BaseModel): param_e: list[str]
2. 建立协议与模型的映射表
用字典绑定协议字符串和对应参数模型,方便后续快速匹配:
PROTOCOL_MODEL_MAP = { "protocol1": ProtocolOneParam, "protocol2": ProtocolTwoParam, "protocol3": ProtocolThreeParam, # 继续添加其他协议的映射关系... }
3. 在Foo模型中添加自定义验证逻辑
使用Pydantic 2.x的@model_validator(mode='before')(若为1.x版本则替换为@root_validator(pre=True)),在模型解析前完成动态匹配:
class Foo(BaseModel): protocol: str protocol_params: Union[ProtocolOneParam, ProtocolTwoParam, ProtocolThreeParam] @model_validator(mode='before') def resolve_protocol_params(cls, values: Dict[str, Any]) -> Dict[str, Any]: protocol = values.get("protocol") params = values.get("protocol_params") if protocol and params: target_model = PROTOCOL_MODEL_MAP.get(protocol) if not target_model: raise ValueError(f"不支持的协议类型: {protocol}") # 手动将参数解析为目标模型 values["protocol_params"] = target_model.model_validate(params) return values
4. 测试验证
用以下代码验证功能是否正常:
# 测试protocol1场景 foo1 = Foo.model_validate({ "protocol": "protocol1", "protocol_params": {"param_a": "test", "param_b": 123} }) print(type(foo1.protocol_params)) # 输出 <class '__main__.ProtocolOneParam'> # 测试protocol2场景 foo2 = Foo.model_validate({ "protocol": "protocol2", "protocol_params": {"param_c": 3.14, "param_d": True} }) print(type(foo2.protocol_params)) # 输出 <class '__main__.ProtocolTwoParam'> # 测试不支持的协议 try: Foo.model_validate({ "protocol": "unknown", "protocol_params": {} }) except ValidationError as e: print(e) # 抛出"不支持的协议类型: unknown"的错误
注意事项
- 若使用Pydantic 1.x,仅需将
@model_validator(mode='before')替换为@root_validator(pre=True),核心逻辑保持不变。 - 后续新增协议时,只需添加对应的参数模型和映射关系,无需修改验证器代码,扩展性极强。
内容的提问来源于stack exchange,提问作者M.Armoun
相关产品推荐
相关产品推荐

