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

在Pydantic中从字典创建模型时不分配默认值的实现方案

实现方案

完全可行,通过自定义Pydantic基类,既能让模型实例仅保留传入的字段(不自动填充默认值),又能保证schema()方法生成的JSON Schema包含原始定义的默认值,同时支持嵌套模型。

核心思路

  1. 自定义基类重写数据预处理逻辑,仅保留传入的字段,跳过默认值自动填充
  2. 确保模型序列化时仅输出实际设置的字段
  3. 嵌套模型继承该基类,实现层级结构的一致行为

代码实现(Pydantic v2)

from pydantic import BaseModel, model_validator, Field
from typing import Optional, Dict, Any

# 自定义基类,实现无默认值填充的逻辑
class NoDefaultBaseModel(BaseModel):
    @model_validator(mode='before')
    def keep_only_provided_fields(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        # 直接返回传入的原始值,不触发默认值填充
        return values

    def model_dump(self, **kwargs):
        # 默认仅序列化实际设置过的字段,和模型实例状态一致
        return super().model_dump(exclude_unset=True, **kwargs)

# 定义嵌套模型,继承自定义基类
class NestedModel(NoDefaultBaseModel):
    nested_field: Optional[str] = "default_nested"
    another_nested: Optional[int] = 123

# 定义主模型,继承自定义基类
class MyModel(NoDefaultBaseModel):
    my_field: Optional[str] = None
    my_other_field: Optional[str] = "aaaaaaaaaaab"
    nested: Optional[NestedModel] = Field(default_factory=lambda: NestedModel())

# 测试逻辑
my_dict = {"my_field": "value", "nested": {"nested_field": "custom_nested"}}
my_model = MyModel(**my_dict)

# 输出模型实例序列化结果:仅包含传入的字段
print(my_model.model_dump())
# 输出: {"my_field": "value", "nested": {"nested_field": "custom_nested"}}

# 输出JSON Schema:保留所有字段的默认值定义
print(MyModel.schema())
# 输出示例(关键片段):
# "my_other_field": {"title": "My Other Field", "type": "string", "default": "aaaaaaaaaaab"},
# "nested": {"$ref": "#/definitions/NestedModel", "default": {"nested_field": "default_nested", "another_nested": 123}}

关键点说明

  • 数据预处理:model_validator(mode='before')在验证前直接返回传入的原始字典,让Pydantic跳过默认值填充逻辑,仅对传入的字段做类型校验
  • 序列化控制:重写model_dump默认启用exclude_unset=True,确保输出和模型实例的实际字段一致
  • 嵌套支持:所有嵌套模型必须继承NoDefaultBaseModel,才能让嵌套层级也遵循相同的无默认值填充规则
  • Schema保留默认值:schema()方法基于模型类的原始字段定义生成,不受实例化逻辑的影响,因此默认值会被完整保留

兼容Pydantic v1的版本

如果使用Pydantic v1,只需将model_validator替换为root_validator(pre=True),model_dump替换为dict(exclude_unset=True):

from pydantic import BaseModel, root_validator, Field
from typing import Optional, Dict, Any

class NoDefaultBaseModel(BaseModel):
    @root_validator(pre=True)
    def keep_only_provided_fields(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        return values

    def dict(self, **kwargs):
        return super().dict(exclude_unset=True, **kwargs)

# 后续模型定义和测试逻辑一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 18:52:44