You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Pydantic根据字典结构自动实例化对应子类BaseModel

问题描述

需要将不同结构的Python字典转换为对应的Pydantic BaseModel实例。现有代码定义了ConditionType枚举、BaseConditionalProps的两个子类ConditionalExpressionProps、CycleDurationTrendProps,以及包含这两个子类的ConditionalConfig和SendNotificationChannel模型。期望通过SendNotificationChannel(**dict)实例化时,根据字典中的cond_type自动将conditional_config的condition_prop实例化为对应子类(如ConditionalExpressionProps或CycleDurationTrendProps),但当前实例化后condition_prop始终是父类BaseConditionalProps,需要解决这个问题。

现有代码

from enum import Enum
from pydantic import BaseModel, Field, Optional

class ConditionType(str, Enum):
    EXPRESSION = 'EXPRESSION'
    CYCLE_DUR_TREND = 'CYCLE_DUR_TREND'

class BaseConditionalProps(BaseModel):
    pass  # 父类为基础空模型

class ConditionalExpressionProps(BaseConditionalProps):
    conditional_expression: str

class CycleDurationTrendProps(BaseConditionalProps):
    direction_up : bool = True
    n : int = Field(1, ge=1, le=1000)

class ConditionalConfig(BaseModel):
    cond_type: ConditionType = ConditionType.EXPRESSION
    condition_prop: BaseConditionalProps

class SendNotificationChannel(BaseModel):
    id: str
    customer_id: str
    conditional_config: Optional[ConditionalConfig]

测试示例

>>> channel = {"id": "1", "customer_id": "c1", "conditional_config" : {"cond_type": "EXPRESSION", "condition_prop":{"conditional_expression":"ALPHA"}}}
>>> channel_obj = SendNotificationChannel(**channel)
>>> channel_obj
SendNotificationChannel(id='1', customer_id='c1', conditional_config=ConditionalConfig(cond_type=<ConditionType.EXPRESSION: 'EXPRESSION'>, condition_prop=BaseConditionalProps()))
>>> channel_obj.conditional_config.condition_prop
BaseConditionalProps()
解决方法

方案1:Pydantic v2 模型验证器(精准匹配)

利用Pydantic v2的model_validator,根据cond_type字段手动将condition_prop映射到对应子类:

from pydantic import model_validator

class ConditionalConfig(BaseModel):
    cond_type: ConditionType = ConditionType.EXPRESSION
    condition_prop: ConditionalExpressionProps | CycleDurationTrendProps

    @model_validator(mode='before')
    def match_condition_prop(cls, values):
        cond_type = values.get('cond_type')
        prop_data = values.get('condition_prop')
        if cond_type == ConditionType.EXPRESSION:
            values['condition_prop'] = ConditionalExpressionProps(**prop_data)
        elif cond_type == ConditionType.CYCLE_DUR_TREND:
            values['condition_prop'] = CycleDurationTrendProps(**prop_data)
        return values

测试验证:

>>> channel_obj = SendNotificationChannel(**channel)
>>> channel_obj.conditional_config.condition_prop
ConditionalExpressionProps(conditional_expression='ALPHA')

方案2:Pydantic v2 鉴别联合类型(规范写法)

通过给父类添加鉴别字段,让Pydantic自动匹配子类,需要调整输入结构将类型标识合并到condition_prop中:

from pydantic import Discriminator, Field

class BaseConditionalProps(BaseModel):
    type: ConditionType

class ConditionalExpressionProps(BaseConditionalProps):
    type: ConditionType = ConditionType.EXPRESSION
    conditional_expression: str

class CycleDurationTrendProps(BaseConditionalProps):
    type: ConditionType = ConditionType.CYCLE_DUR_TREND
    direction_up : bool = True
    n : int = Field(1, ge=1, le=1000)

class ConditionalConfig(BaseModel):
    condition_prop: BaseConditionalProps = Field(discriminator='type')

调整后的输入示例:

>>> channel = {"id": "1", "customer_id": "c1", "conditional_config" : {"condition_prop":{"type": "EXPRESSION", "conditional_expression":"ALPHA"}}}
>>> channel_obj = SendNotificationChannel(**channel)
>>> channel_obj.conditional_config.condition_prop
ConditionalExpressionProps(type=<ConditionType.EXPRESSION: 'EXPRESSION'>, conditional_expression='ALPHA')

方案3:Pydantic v1 字段验证器(兼容旧版本)

如果使用Pydantic v1,用@validator实现类型映射:

from pydantic import validator

class ConditionalConfig(BaseModel):
    cond_type: ConditionType = ConditionType.EXPRESSION
    condition_prop: BaseConditionalProps

    @validator('condition_prop', pre=True, always=True)
    def validate_condition_prop(cls, v, values):
        cond_type = values.get('cond_type')
        if cond_type == ConditionType.EXPRESSION:
            return ConditionalExpressionProps(**v)
        elif cond_type == ConditionType.CYCLE_DUR_TREND:
            return CycleDurationTrendProps(**v)
        return BaseConditionalProps(**v)

测试效果与方案1一致。

内容的提问来源于stack exchange,提问作者Ouroboros

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:01:24