新闻中心
Marshmallow 序列化:将模型字段包装为嵌套结构

本教程详细介绍了如何使用 Marshmallow 库将模型实例中的简单字符串字段(如 ID)在序列化时转换为嵌套的 JSON 对象。通过定义一个带有 `pre_dump` 钩子的嵌套 Schema,我们能够优雅地将扁平数据结构转换为复杂的嵌套结构,从而满足特定的输出格式要求,确保数据结构清晰且易于维护。
Marshmallow 序列化:将模型字段包装为嵌套结构
在数据序列化过程中,我们经常需要将模型实例中的某个简单字段(例如一个 ID 字符串)转换为一个嵌套的 JSON 对象,以满足特定的 API 规范或前端展示需求。Marshmallow 提供了强大且灵活的机制来实现这一目标,特别是通过结合 fields.Nested 和 Schema 的 pre_dump 钩子。
场景描述
假设我们有一个用户模型实例,其中包含一个 parent 属性,它是一个字符串,表示父级用户的 ID。我们希望在序列化该用户实例时,将 parent ID 包装成 { "id": "..." } 这样的嵌套对象,而不是一个简单的字符串。
期望的输出格式:
{
"name": "John",
"parent": {
"id": "123-345"
}
}解决方案:使用 fields.Nested 和 pre_dump
为了实现上述目标,我们将定义两个 Marshmallow Schema:一个用于包装 ID 的嵌套 Schema,另一个是主用户 Schema。关键在于在嵌套 Schema 中使用 pre_dump 钩子来预处理传入的原始数据。
1. 定义嵌套 ID Schema
首先,我们创建一个 IdSchema,它将负责处理 ID 字段。由于原始数据只是一个字符串 ID,而不是一个字典,我们需要在 IdSchema 内部将这个字符串转换为一个字典,以便 fields.String() 能够正确地提取 id 键的值。
Musho
AI网页设计Figma插件
76
查
看详情
from marshmallow import Schema, fields, pre_dump
class IdSchema(Schema):
"""
用于包装单个 ID 字符串为 {"id": "..."} 格式的 Schema。
"""
id = fields.String(required=True)
@pre_dump
def wrap_id_into_dict(self, data, **kwargs):
"""
在序列化之前,将传入的原始 ID 字符串包装成一个字典。
例如,如果 data 是 "123-345",则返回 {"id": "123-345"}。
"""
if isinstance(data, str):
return {"id": data}
# 如果数据已经是字典形式,则直接返回,避免不必要的包装
return data@pre_dump 解释:@pre_dump 装饰器标记的方法会在 Schema 的字段被处理之前执行。当 UserSchema 中的 parent = fields.Nested(IdSchema) 被调用时,UserSchema 会将模型实例的 parent 属性(例如 "123-345" 字符串)传递给 IdSchema。此时,wrap_id_into_dict 方法会接收到这个字符串,并将其转换成 {"id": "123-345"} 字典。这个转换后的字典随后会被 IdSchema 的 id = fields.String() 字段正确处理。
2. 定义用户 Schema
接下来,我们定义 UserSchema,其中 parent 字段将使用 fields.Nested(IdSchema) 来引用我们刚刚创建的 IdSchema。
class UserSchema(Schema):
"""
用户模型的主 Schema,包含嵌套的 parent ID 字段。
"""
name = fields.String(required=True)
parent = fields.Nested(IdSchema, allow_none=True) # allow_none 允许 parent 为空3. 完整示例代码
结合上述两个 Schema,我们可以构建一个完整的示例来演示其工作原理。
from marshmallow import Schema, fields, pre_dump
import json
# 1. 定义 IdSchema
class IdSchema(Schema):
id = fields.String(required=True)
@pre_dump
def wrap_id_into_dict(self, data, **kwargs):
if isinstance(data, str):
return {"id": data}
return data
# 2. 定义 UserSchema
class UserSchema(Schema):
name = fields.String(required=True)
parent = fields.Nested(IdSchema, allow_none=True)
# 3. 模拟模型实例
class UserModel:
def __init__(self, name, parent_id=None):
self.name = name
self.parent = parent_id # parent 是一个字符串 ID
# 4. 实例化模型并序列化
if __name__ == "__main__":
# 示例 1: 包含 parent ID
user_with_parent = UserModel(name="John Doe", parent_id="123-345")
user_schema = UserSchema()
result_with_parent = user_schema.dump(user_with_parent)
print("序列化结果 (带父级ID):")
print(json.dumps(result_with_parent, indent=2, ensure_ascii=False))
print("\n" + "="*30 + "\n")
# 示例 2: 不包含 parent ID
user_without_parent = UserModel(name="Jane Smith")
result_without_parent = user_schema.dump(user_without_parent)
print("序列化结果 (不带父级ID):")
print(json.dumps(result_without_parent, indent=2, ensure_ascii=False))运行上述代码,将得到以下输出:
序列化结果 (带父级ID):
{
"name": "John Doe",
"parent": {
"id": "123-345"
}
}
==============================
序列化结果 (不带父级ID):
{
"name": "Jane Smith",
"parent": null
}注意事项与总结
- @pre_dump 的强大作用: pre_dump 钩子是 Marshmallow 中一个非常强大的特性,它允许你在序列化过程的早期阶段对原始数据进行转换。这对于处理不完全匹配 Schema 结构但需要转换的数据特别有用。
- 数据类型匹配: 当使用 fields.Nested 时,Marshmallow 期望传入的数据是字典或可迭代对象。如果传入的是一个简单类型(如字符串、整数),并且需要将其转换为嵌套对象,那么在嵌套 Schema 中使用 pre_dump 进行预处理是最佳实践。
- 可重用性: IdSchema 可以被其他任何需要将 ID 字符串包装为 {"id": "..."} 格式的 Schema 重用,提高了代码的模块化和可维护性。
- allow_none=True: 在 UserSchema 中为 parent 字段设置 allow_none=True 是一个好的习惯,以应对模型实例中 parent 属性可能为 None 的情况,避免序列化错误。
通过这种方法,我们成功地将模型实例中的扁平 ID 字符串在序列化时转换为了所需的嵌套对象结构,同时保持了 Marshmallow Schema 的清晰和专业性。
以上就是Marshmallow 序列化:将模型字段包装为嵌套结构的详细内容,更多请关注其它相关文章!
# 用户登录
# 丽水市全域营销推广公司
# 太原seo站内优化技巧
# 郑州百度网站推广软件
# 萝岗企业网站推广
# 好博客seo优化技术
# 淘宝营销模式推广
# seo网站内部优化_品达公关
# 澳门关键词优化排名
# 厦门湖里百度营销推广
# seo职业培训机构排名
# 操作流程
# 的是
# js
# 不带
# 迭代
# 原始数据
# 数据结构
# 是一个
# 转换为
# 序列化
# red
# 可迭代对象
# ai
# json
# 前端
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
照顾宝贝2小游戏点击立即在线玩
拼多多视频播放卡顿如何处理 拼多多视频播放优化技巧
如何在更新Composer依赖后自动运行测试_使用post-update-cmd钩子触发PHPUnit
J*a实现学校排课程序_面向对象结构化项目示例
快速CSGO开箱网站指南 CSGO开箱平台推荐
2025-2030年全球乘用车销量预测:新能源成增长主力
深入理解J*a链表中的IPosition接口与使用
Kafka Streams中基于消息头条件过滤消息的实现指南
React项目中导航栏Logo自适应布局:避免裁剪与布局溢出
C++如何实现异步操作_C++11使用std::future和std::async进行异步编程
Eclipse怎么运行工程_Eclipse工程运行配置说明
深入理解Go语言中Map值与方法接收器的交互:为什么需要临时变量
msn官网入口地址手机版 msn官方网站手机最新链接
HTML长属性值处理:表单action路径优化与代码规范应对
C#使用XPath查询节点时出错? 常见语法错误与调试技巧
格力空气能E5故障代码是什么情况_格力空气能E5代码解析与应对措施
AO3官网镜像链接 Archive of Our Own同人文在线浏览
CSS条件样式无法按设备触发怎么排查_media条件语句正确设置解决触发问题
Linux如何构建多环境配置管理_Linux多环境配置方案
在VS Code中配置和运行Dart程序的完整步骤
CSS图片焦点样式实现教程:理解与应用tabindex属性
Animex动漫社网入口地址 Animex动漫社网正版在线入口
CSS布局:解决全屏元素100%尺寸与外边距导致的页面溢出问题
漫蛙漫画登录站点 漫蛙2正版漫画快速访问
邮政快递包裹最新位置 邮政快递实时追踪入口
163邮箱官方主页登录 直达网易邮箱登录核心页面
大象笔记网页版入口 印象笔记网页版登录入口
快手赚钱渠道_快手收益来源
谷歌浏览器浏览体验优化_谷歌浏览器新版直连永久可用提示
Golang指针如何与map组合使用_Golang map指针组合实践
邮政快递单号查询入口 邮政快递物流信息在线查询入口
美团外卖商家服务中心入口 美团商家版官网入口
C++ string find函数返回值npos详解_C++字符串查找失败的判断条件
机器学习中对数变换预测结果的反向还原
Win11如何开启讲述人功能 Win11屏幕阅读器(讲述人)开启与关闭【教程】
圆通快递查询实时追踪 圆通物流包裹状态快速查看
微信商城在哪里打开【步骤】
期待已久:小米17 Ultra、小米首款NAS本月登场
处理嵌套交互式控件:前端可访问性指南
React列表渲染与独立状态管理:避免全局状态影响局部更新
谷歌浏览器最新官方入口链接 谷歌浏览器网页版官网导航
css卡片内容溢出如何处理_使用overflow隐藏或scroll显示内容
内存检查:在VS Code中调试C++时的内存视图
妖精动漫免费平台 妖精动漫官网资源观看网址
文心一言怎样用插件调度API数据_文心一言用插件调度API数据【API调用】
在Go开发中优雅管理ListenAndServe进程:GoSublime集成方案
如何优雅地扩展SprykerGlue后端API授权逻辑,使用spryker/glue-backend-api-application-authorization-connector-extension
TikTok网页版直接登录 TikTok网页端官方平台入口
win11 arm版怎么安装 M1/M2 Mac虚拟机安装ARM win11的方法
C++如何打印当前代码行号与文件名_C++预定义宏FILE与LINE的使用


2025-11-02
浏览次数:次
返回列表