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

DDD
发布: 2025-11-02 14:07:22
原创
646人浏览过

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 键的值。

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

豆包大模型 834
查看详情 豆包大模型
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 序列化:将模型字段包装为嵌套结构的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号