当前位置: 首页 > news >正文

【Python】在 Pydantic 模型中使用非 Pydantic 定义的类作为模型字段类型

文章目录

    • 前言
    • 模型字段为对象类型时
    • 模型字段为对象列表类型时

前言

Pydantic 模型中使用非 Pydantic 定义的类作为模型字段类型时,核心问题是让 Pydantic 能够​​正确解析输入数据​​(如 JSON/字典)为自定义类的实例,并​​可选地序列化回原始格式​​。

场景假设:假设我们有一个普通 PythonUser(非 Pydantic 模型):

# 自定义类,非 Pydantic 模型
class User:def __init__(self, name: str, age: int):self.name = nameself.age = agedef __repr__(self):return f"User(name={self.name}, age={self.age})"

Pydantic v2 支持 BeforeValidator,可以在数据被解析到模型字段前进行预处理,适合需要对原始输入做复杂转换的场景。

模型字段为对象类型时

步骤说明

  1. 导入 BeforeValidatorAnnotated
  2. 定义预处理函数(如将字典转为 Use实例)。
  3. Pydantic模型设置arbitrary_types_allowed=True,表明可以包含任意类型的字段,比如自定义类、第三方库的对象等。否则,Pydantic 默认只允许标准类型和已注册的类型。
  4. 使用 Annotated[User, BeforeValidator(preprocess_func)]标记字段类型。
from typing import Annotatedfrom pydantic import BaseModel, BeforeValidator# 预处理函数:将输入转为 User 实例
def preprocess_user(value: dict) -> User:if not isinstance(value, dict):raise ValueError("Expected dict for User")return User(**value)# Pydantic 模型(使用 Annotated 绑定 BeforeValidator)
class Profile(BaseModel, arbitrary_types_allowed=True):user_info: Annotated[User, BeforeValidator(preprocess_user)]if __name__ == '__main__':# 测试:从字典解析data = {"user_info": {"name": "Diana", "age": 28}}profile = Profile(**data)print(profile.user_info)  # 输出:User(name=Diana, age=28)

模型字段为对象列表类型时

与模型字段为对象类型时的处理方式大同小异

from typing import List, Annotatedfrom pydantic import BaseModel, BeforeValidator# 预处理函数:将字典列表转为 User 实例列表
def preprocess_user_list(value: List[dict]) -> List[User]:user_infos = []for idx, item in enumerate(value):if not isinstance(item, dict):raise ValueError(f"Element {idx} in user_infos is not a dict")user_infos.append(User(**item))return user_infos# Pydantic 模型(使用 Annotated 绑定 BeforeValidator)
class Profile(BaseModel, arbitrary_types_allowed=True):user_infos: Annotated[List[User], BeforeValidator(preprocess_user_list)]# 配置序列化(同上)model_config = {"json_encoders": {User: lambda u: {"name": u.name, "age": u.age}}}if __name__ == '__main__':# 测试:从字典列表解析data = {"user_infos": [{"name": "Diana", "age": 28},{"name": "Eve", "age": 22}]}profile = Profile(**data)print(profile.user_infos)  # 输出:[User(name=Diana, age=28), User(name=Eve, age=22)]
http://www.dtcms.com/a/349310.html

相关文章:

  • Java项目-苍穹外卖_Day2
  • 8 设计URL短链
  • rust语言 (1.88) egui (0.32.1) 学习笔记(逐行注释)(二十) 文件、文件夹选择框、保存文件框
  • qt配置ros2环境,简单版本
  • Rust:变量、常量与数据类型
  • 2025 突出的时序模型
  • 【C语言强化训练16天】--从基础到进阶的蜕变之旅:Day13
  • Linux-Redis的安装
  • 第四章:并发编程的基石与高级模式之Select语句与多路复用
  • 【Linux】开发工具命令指南:深度解析Vim的使用操作
  • Allegro17.4导出带有NET的PDF文档及组装样式图
  • MongoDB vs MySQL:NoSQL 和 SQL 的核心区别与适用场景
  • 前端开发:详细介绍npm、pnpm和cnpm分别是什么,使用方法以及之间有哪些关系
  • CPTS-Pressed复现(XML-RPC)
  • Python 面向对象进阶:深入理解封装、继承与多态
  • 【C++】第二十六节—C++11(中) | 右值引用和移动语义(续集)+lambda
  • 验证码流程
  • 【AMBA总线互联IP】
  • 6、RocketMQ消息积压问题如何解决
  • QSpinBox的用法及其使用QSS对其美化
  • 【ElasticSearch】json查询语法和可用的客户端
  • Docker 在线安装 RabbitMQ
  • 开源 C++ QT Widget 开发(五)通讯--串口调试
  • NILMTK(非侵入式负载监测工具包)安装
  • Linux 进阶之性能调优,文件管理,网络安全
  • AI精准种植改写农业格局:亩产量提升18%+水资源利用率提高32%,破解小农户技术门槛难题
  • Linux下usb设备驱动涉及的结构体
  • More Effective C++ 条款06: 区分自增自减操作符的前缀和后缀形式
  • 04-ArkTS编程语言入门
  • 分享些 Function 和 枚举的经典使用案例