Marshmallow 数据预处理与后处理方法详解

Marshmallow 数据预处理与后处理方法详解

marshmallow A lightweight library for converting complex objects to and from simple Python datatypes. marshmallow 项目地址: https://gitcode.com/gh_mirrors/ma/marshmallow

概述

Marshmallow 是一个强大的 Python 库,用于对象序列化和反序列化。在实际应用中,我们经常需要在数据序列化(dump)或反序列化(load)前后对数据进行处理。Marshmallow 提供了灵活的装饰器 API 来实现这些预处理和后处理操作。

核心装饰器方法

Marshmallow 提供了四个主要装饰器来处理数据转换的不同阶段:

  1. @pre_load - 在反序列化(load)前执行
  2. @post_load - 在反序列化后执行
  3. @pre_dump - 在序列化(dump)前执行
  4. @post_dump - 在序列化后执行

这些装饰器可以让我们在数据转换的各个阶段插入自定义逻辑,实现复杂的数据处理需求。

基本用法示例

让我们看一个简单的例子,展示如何在反序列化后处理数据:

from marshmallow import Schema, fields, post_load

class UserSchema(Schema):
    name = fields.Str()
    slug = fields.Str()

    @post_load
    def slugify_name(self, in_data, **kwargs):
        in_data["slug"] = in_data["slug"].lower().strip().replace(" ", "-")
        return in_data

schema = UserSchema()
result = schema.load({"name": "Steve", "slug": "Steve Loria "})
print(result["slug"])  # 输出: 'steve-loria'

在这个例子中,@post_load 装饰器标记的方法会在数据反序列化后被调用,我们可以在这里对数据进行进一步处理。

处理多个对象

默认情况下,预处理和后处理方法每次只处理一个对象。如果需要处理对象集合,可以在装饰器中设置 pass_many=True

@pre_load(pass_many=True)
def process_collection(self, data, many, **kwargs):
    if many:
        # 处理对象集合
        return [item for item in data if item is not None]
    # 处理单个对象
    return data

实际应用:数据封装与解封装

一个常见的应用场景是在序列化时将数据封装到命名空间中,在反序列化时解封装:

from marshmallow import Schema, fields, pre_load, post_load, post_dump

class BaseSchema(Schema):
    __envelope__ = {"single": None, "many": None}
    
    def get_envelope_key(self, many):
        key = self.__envelope__["many"] if many else self.__envelope__["single"]
        assert key is not None, "Envelope key undefined"
        return key

    @pre_load(pass_many=True)
    def unwrap_envelope(self, data, many, **kwargs):
        key = self.get_envelope_key(many)
        return data[key]

    @post_dump(pass_many=True)
    def wrap_with_envelope(self, data, many, **kwargs):
        key = self.get_envelope_key(many)
        return {key: data}

class UserSchema(BaseSchema):
    __envelope__ = {"single": "user", "many": "users"}
    name = fields.Str()
    email = fields.Email()

这种模式在构建 REST API 时特别有用,可以保持响应数据的一致结构。

错误处理

在预处理和后处理方法中,我们可以抛出 ValidationError 来处理错误情况:

from marshmallow import ValidationError, pre_load

class BandSchema(Schema):
    name = fields.Str()

    @pre_load
    def validate_input(self, data, **kwargs):
        if "data" not in data:
            raise ValidationError('输入数据必须包含"data"键', "_preprocessing")
        return data["data"]

方法执行顺序

理解处理方法的执行顺序非常重要:

反序列化流程:

  1. @pre_load(pass_many=True) 方法
  2. @pre_load(pass_many=False) 方法
  3. 执行 load() 进行验证和反序列化
  4. 字段验证器 @validates
  5. 模式验证器 @validates_schema
  6. @post_load(pass_many=True) 方法
  7. @post_load(pass_many=False) 方法

序列化流程:

  1. @pre_dump(pass_many=False) 方法
  2. @pre_dump(pass_many=True) 方法
  3. 执行 dump() 进行序列化
  4. @post_dump(pass_many=False) 方法
  5. @post_dump(pass_many=True) 方法

重要注意事项

  1. 执行顺序不保证:相同类型的多个装饰器方法的执行顺序是不确定的。如果需要确保执行顺序,应该将逻辑合并到一个方法中。

  2. 推荐做法

# 推荐:将依赖步骤放在同一个方法中
@pre_load
def preprocess(self, data, **kwargs):
    step1_data = self.step1(data)
    step2_data = self.step2(step1_data)
    return step2_data
  1. 不推荐做法
# 不推荐:依赖多个装饰器方法的执行顺序
@pre_load
def step1(self, data, **kwargs): ...

@pre_load
def step2(self, data, **kwargs): ...

总结

Marshmallow 的预处理和后处理方法提供了强大的灵活性,让我们可以在数据序列化和反序列化的各个阶段插入自定义逻辑。通过合理使用这些方法,我们可以实现复杂的数据转换需求,同时保持代码的清晰和可维护性。

marshmallow A lightweight library for converting complex objects to and from simple Python datatypes. marshmallow 项目地址: https://gitcode.com/gh_mirrors/ma/marshmallow

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殷巧或

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值