如何获取 Pydantic 对象中的必需属性?

来源:站长论坛作者:深圳网站建设头衔:草根站长
导读:本期聚焦于小伙伴创作的《如何获取 Pydantic 对象中的必需属性?》,敬请观看详情。在定义数据模型时,区分哪些字段是用户必须提供、哪些有默认值,是接口校验和配置管理的常见需求。Pydantic 在 V2 版本中通过 model_fields 暴露了每个字段的元数据,其中 required 标志直接表示是否必填。不同于遍历实例属性,从模型类层面读取元数据可以避免实例化时的校验开销,也能在动态生成表单或 OpenAPI 文档时直接使用。实际编码中,可以结合字段的 annotation 与 required 值,过滤出真正强制的字段名列表,比解析源码或捕获验证错误更稳定。理解这一机制,有助于写出更通用的模型 introspection 工具函数。

在使用 Pydantic 构建数据模型时,我们经常需要在不创建实例的情况下,知道哪些字段是调用方必须传入的。Pydantic V2 提供了完善的元数据接口,让这件事变得非常简单且可靠。

如何获取 Pydantic 对象中的必需属性?

为什么不能直接看实例属性

很多初学者会尝试先创建一个对象,再去看哪些属性没有默认值。这种做法有两个明显问题:第一,如果模型里有一些带复杂校验的必填字段,为了“探测”而实例化可能会触发校验错误;第二,实例化本身就需要提供必填项,这就变成了先有鸡还是先有蛋的问题。

Pydantic 的设计思路是把字段的定义信息和运行时的实例数据分开。模型类上的 model_fields 是一个字典,键是字段名,值是一个 FieldInfo 对象,里面记录了类型、默认值、是否必填等元信息。我们完全可以在类级别完成必需属性的提取。

使用 model_fields 获取必需属性

在 Pydantic V2 中,每个字段对应的 FieldInfo 都有一个 is_required() 方法,也可以直接访问其 required 属性。最直观的方式是遍历 model_fields,把 required 为 True 的字段名收集起来。

下面是一段可复用的工具函数示例,它接收一个 Pydantic 模型类,返回必需字段的列表:

from pydantic import BaseModel, Field

class UserProfile(BaseModel):
    user_id: int
    name: str = Field(default='匿名用户')
    email: str
    age: int | None = None

def get_required_fields(model_cls):
    required = []
    for field_name, field_info in model_cls.model_fields.items():
        # required 为 True 表示调用方必须提供该字段
        if field_info.required:
            required.append(field_name)
    return required

if __name__ == '__main__':
    print(get_required_fields(UserProfile))
    # 输出: ['user_id', 'email']

在上面的代码中,user_idemail 没有默认值,因此被标记为必需;而 nameage 由于设置了默认值或可选类型,不在结果中。这种方式不依赖任何实例化操作,执行效率很高。

处理 Optional 与带默认值的字段

有一个容易混淆的点:像 age: int | None = None 这样的字段,虽然类型是可选的,但因为给了默认值 None,所以并不是必需字段。反过来,如果写成 age: int | None 且没有默认值,那它依然是必需的,因为调用方必须显式传一个值(可以是 None)。

我们可以通过对比来验证这一行为:

from pydantic import BaseModel

class DemoModel(BaseModel):
    a: int
    b: int | None
    c: int | None = None

for name, info in DemoModel.model_fields.items():
    print(name, 'required =', info.required)
# 输出:
# a required = True
# b required = True
# c required = False

从输出可以看出,b 虽然是可选类型,但因为没有默认值,Pydantic 仍将其视为必需属性。这说明“必需”的判断标准是“是否必须传参”,而不是“类型是否可为空”。

在动态场景中的实际应用

获取必需属性在不少工程场景中都很有用。例如,在写通用的 API 参数解析层时,可以根据必需字段自动生成错误提示;或者在做配置加载器时,对缺失的必需配置提前报错,而不是等用到时才发现。

我们也可以把提取逻辑封装成类装饰器或 mixin,让所有模型自带 required_fields() 方法:

from pydantic import BaseModel

class WithRequired(BaseModel):
    @classmethod
    def required_fields(cls):
        return [k for k, v in cls.model_fields.items() if v.required]

class Product(WithRequired):
    sku: str
    price: float
    discount: float = 0.0

print(Product.required_fields())
# 输出: ['sku', 'price']

这种写法让模型自身具备 introspection 能力,调用方不需要知道 Pydantic 内部细节,直接通过语义化方法拿到必需字段。对于中大型项目,能明显减少重复代码。

与 Pydantic V1 的差异说明

如果你还在使用 Pydantic V1,获取必需属性的方式略有不同。V1 中通常使用 __fields__ 以及 field.required 属性,且对 Optional 的处理依赖 allow_none 标志。升级到 V2 后,统一使用 model_fieldsFieldInfo.required,接口更加清晰。

如果需要在兼容层写代码,可以先判断是否存在 model_fields 属性:

def get_required(model_cls):
    if hasattr(model_cls, 'model_fields'):
        fields = model_cls.model_fields
    else:
        fields = model_cls.__fields__
    return [k for k, v in fields.items() if getattr(v, 'required', False)]

# 在 V2 模型上调用
from pydantic import BaseModel

class Item(BaseModel):
    id: int
    tag: str = 'default'

print(get_required(Item))
# 输出: ['id']

通过这种兼容写法,老项目迁移时不必一次性改完所有调用点,可以平滑过渡到新版本。

小结

获取 Pydantic 对象中的必需属性,核心就是读取模型类的字段元数据,而非依赖实例。利用 model_fields 配合 required 标志,可以写出零成本、可读性高的工具函数。理解必需与可选的真正判定逻辑,能帮我们避开类型注解带来的直觉误区,也让动态校验和配置管理更加稳健。

Pydanticmodel_fieldsrequired_fields修改时间:2026-08-09 03:03:12

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。