新闻中心

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

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

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 Musho

AI网页设计Figma插件

Musho 76 看详情 Musho
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
}

注意事项与总结

  1. @pre_dump 的强大作用: pre_dump 钩子是 Marshmallow 中一个非常强大的特性,它允许你在序列化过程的早期阶段对原始数据进行转换。这对于处理不完全匹配 Schema 结构但需要转换的数据特别有用。
  2. 数据类型匹配: 当使用 fields.Nested 时,Marshmallow 期望传入的数据是字典或可迭代对象。如果传入的是一个简单类型(如字符串、整数),并且需要将其转换为嵌套对象,那么在嵌套 Schema 中使用 pre_dump 进行预处理是最佳实践。
  3. 可重用性: IdSchema 可以被其他任何需要将 ID 字符串包装为 {"id": "..."} 格式的 Schema 重用,提高了代码的模块化和可维护性。
  4. 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的使用 

搜索