能否分步构建Pydantic BaseModel并延迟至完成后再验证?
问题描述
我正在开发一个处理数据库查询并返回Pydantic模型的数据访问包。核心问题是:多数模型需要关联多张表的数据,仅查询主表无法获取模型的全部属性,必须通过外键关联其他表补充数据。
当前临时方案是把这些缺失的属性设为Optional,分步构建模型:先通过数据库查询返回的字典用model_validate()实例化模型,再手动补充关联表的属性。示例代码如下:
with self.connection.cursor(dictionary=True, buffered=True) as cursor: cursor.execute(query) result = cursor.fetchone() datasets = [] while isinstance(result, dict): dataset = DatasetModel.model_validate(result) dataset.format = FormatModel.model_validate(result) dataset.scans = self.scan_access.get(dataset_ids=[result["dataset_id"]]) result = cursor.fetchone()
但实际上这些属性并非可选,使用该包的业务代码需要加大量assert才能消除IDE的类型提示问题。我不想提前修改查询返回的字典,也不想创建多套表映射模型,想问:是否可以分步构建模型,仅在所有属性补充完成后再执行验证?
解决方案
完全可以利用Pydantic的model_construct()方法实现分步构建+最终验证的需求:
- 用
model_construct()创建未验证的实例:这个方法会跳过所有验证逻辑,直接基于传入的字段创建模型实例,适合先填充部分属性的场景。 - 分步补充关联属性:延续你之前的逻辑,从关联表查询数据并赋值给模型实例。
- 最终执行全量验证:调用
model_validate()方法,传入已填充完整属性的实例,触发Pydantic的全量验证逻辑,确保所有必填字段都已正确设置。
修改后的示例代码:
with self.connection.cursor(dictionary=True, buffered=True) as cursor: cursor.execute(query) result = cursor.fetchone() datasets = [] while isinstance(result, dict): # 1. 创建未验证的模型实例,跳过初始验证 dataset = DatasetModel.model_construct(**result) # 2. 分步补充关联表属性 dataset.format = FormatModel.model_validate(result) dataset.scans = self.scan_access.get(dataset_ids=[result["dataset_id"]]) # 3. 执行全量验证,确保所有必填字段合规 validated_dataset = DatasetModel.model_validate(dataset) datasets.append(validated_dataset) result = cursor.fetchone()
关键说明
model_construct()是Pydantic v1和v2都支持的方法,不会检查字段缺失或类型匹配,仅用于快速构建临时实例。- 最终的
model_validate()会严格按照模型定义验证所有字段,包括必填项的存在性、类型匹配等,确保模型实例的合法性。 - 你可以把
DatasetModel中的关联属性改回必填类型(去掉Optional),业务代码无需再写大量assert,IDE的类型提示也会恢复正常。
内容的提问来源于stack exchange,提问作者Roland Deschain
相关产品推荐
相关产品推荐

