Pydantic如何将单键Dict结构分解为包含op_name等字段的Model?
实现方案
可以通过Pydantic的自定义校验+自定义序列化能力实现需求,完全兼容原始输入输出格式的同时,直接暴露三个一级字段,以下分别提供Pydantic v2(主流版本)和Pydantic v1的实现:
Pydantic v2 实现
from pydantic import BaseModel, model_validator, model_serializer class Model(BaseModel): op_name: str lvalue: str rvalue: str # 反序列化逻辑:将原始结构拆解为三个字段 @model_validator(mode="before") @classmethod def parse_raw_struct(cls, value): if not isinstance(value, dict) or len(value) != 1: raise ValueError("输入必须为仅含1个键的字典") op_name, expr_list = next(iter(value.items())) if not isinstance(expr_list, list) or len(expr_list) != 2: raise ValueError("字典值必须为含2个元素的列表") return { "op_name": op_name, "lvalue": expr_list[0], "rvalue": expr_list[1] } # 序列化逻辑:转换回原始结构保证兼容 @model_serializer() def serialize_to_raw_struct(self): return {self.op_name: [self.lvalue, self.rvalue]}
效果测试
d = { "==": [ "%var%", "10" ] } # 反序列化 m = Model.model_validate(d) print(m.op_name) # 输出 == print(m.lvalue) # 输出 %var% print(m.rvalue) # 输出 10 # 序列化,与原始格式完全一致 print(m.model_dump()) # 输出 {'==': ['%var%', '10']} print(m.model_dump_json()) # 输出 {"==": ["%var%", "10"]}
Pydantic v1 兼容实现
如果使用Pydantic v1版本,可以用以下代码实现相同效果:
from pydantic import BaseModel, root_validator class Model(BaseModel): op_name: str lvalue: str rvalue: str @root_validator(pre=True) def parse_raw_struct(cls, value): if not isinstance(value, dict) or len(value) != 1: raise ValueError("输入必须为仅含1个键的字典") op_name, expr_list = next(iter(value.items())) if not isinstance(expr_list, list) or len(expr_list) != 2: raise ValueError("字典值必须为含2个元素的列表") return { "op_name": op_name, "lvalue": expr_list[0], "rvalue": expr_list[1] } def dict(self, **kwargs): return {self.op_name: [self.lvalue, self.rvalue]} def json(self, **kwargs): return super().json(encoder=lambda obj: obj.dict(), **kwargs)
内容的提问来源于stack exchange,提问作者Anton Ovsyannikov
相关产品推荐
相关产品推荐

