如何基于Pydantic中其他字段的字符串值构建模型?
解决Pydantic基于字符串字段区分模型的问题
错误原因分析
你当前的模型定义逻辑错误:Model类中的model字段被声明为Union[ModelA, ModelB],这意味着Pydantic期望model键对应的值是一个符合ModelA或ModelB结构的嵌套对象,但你的输入JSON是顶层直接包含model和业务字段(比如{"model": "model_a", "some_value": "value_a"}),两者结构不匹配,因此报错"输入需为有效字典或对象而非字符串"。
正确实现方案
核心思路是:让所有子模型共享一个包含鉴别字段(model)的基类,通过固定每个子模型的model字段值,结合Pydantic的discriminator实现自动路由解析。
步骤1:引入依赖并定义基类
from typing import Annotated, Union, Literal from pydantic import BaseModel, Field, RootModel
class BaseModelWithType(BaseModel): model: str
步骤2:定义子模型并固定鉴别字段值
用Literal约束每个子模型的model字段为唯一值,确保Pydantic能准确区分:
class ModelA(BaseModelWithType): model: Literal["model_a"] = "model_a" some_value: str class ModelB(BaseModelWithType): model: Literal["model_b"] = "model_b" another_value: str
步骤3:定义顶层解析模型
有两种常用方式:
方式1:使用RootModel(推荐)
RootModel可以直接接收顶层JSON对象,无需额外嵌套:
class AnyModel(RootModel[Annotated[Union[ModelA, ModelB], Field(discriminator="model")]]): pass
方式2:直接用Union验证
无需额外定义顶层模型,直接使用model_validate验证输入:
# 定义类型别名方便复用 ModelUnion = Annotated[Union[ModelA, ModelB], Field(discriminator="model")]
测试验证
# 解析ModelA输入 input_a = {"model": "model_a", "some_value": "value_a"} result_a = AnyModel.model_validate(input_a) print(type(result_a.root)) # <class '__main__.ModelA'> print(result_a.root.some_value) # value_a # 解析ModelB输入 input_b = {"model": "model_b", "another_value": "value_b"} result_b = ModelUnion.model_validate(input_b) print(type(result_b)) # <class '__main__.ModelB'> print(result_b.another_value) # value_b
关键说明
discriminator="model"告诉Pydantic通过model字段的值来判断应该使用哪个子模型解析输入。Literal约束确保每个子模型的model字段值唯一,避免解析歧义。- 子模型必须继承包含鉴别字段的基类,否则Pydantic无法识别共同的鉴别字段。
内容的提问来源于stack exchange,提问作者Stefan Andersson
相关产品推荐
相关产品推荐

