bigywater.tech
Flask · 115

Marshmallow 序列化

Marshmallow 的 dump 与 load 各做了什么?错误信息长什么样?未知字段怎么处理?类型转换有多宽松?性能代价有多大?这篇逐项运行并打印每种情况的结果。

不泄漏
dump 只输出声明过的字段,没声明的 secret 与 load_only 的 password 都不会出现
5.5 → 5
Int 字段把小数悄悄截断成整数
约 23 倍
dump 10000 个对象相对手写字典推导的耗时

dump

实测 · 本机执行输出
   {"id": 1, "name": "ann", "email": "ann@x.test", "created": "2026-01-02T03:04:05", "balance": "10.50", "display": "ann <ann@x.test>", "posts": [], "fullName": "ann"}
  对象上的 secret、password 属性: False / False (没声明或 load_only 的不会泄漏)
  data_key 改名:fullName = ann | Method 字段 display = ann <ann@x.test> | Decimal as_string: '10.50' | 日期: 2026-01-02T03:04:05

上一篇:OpenAPI 文档生成;下一篇:Pydantic 在 Flask 中的使用。

load 与错误结构

实测 · 本机执行输出
  合法输入 → {'name': 'bob', 'email': 'b@x.test', 'password': 'pw', 'balance': Decimal('3.14')}
  什么都没给                      → {"name": ["Missing data for required field."], "email": ["Missing data for required field."], "password": ["Missing data for required field."]}
  多个字段同时出错                   → {"name": ["Length must be between 1 and 20."], "email": ["Not a valid email address."]}
  类型不对(name 是数字)             → {"name": ["Not a valid string."]}
  嵌套的 posts 有错               → {"posts": {"1": {"title": ["Missing data for required field."]}}}
  传了 dump_only 的 id          → {"id": ["Unknown field."]}

未知字段

实测 · 本机执行输出
  RAISE(默认)                  → {"extra": ["Unknown field."]}
  EXCLUDE                    → 通过 {'name': 'a', 'email': 'a@x.test', 'password': 'pw'}
  INCLUDE                    → 通过 {'name': 'a', 'email': 'a@x.test', 'password': 'pw', 'extra': 1}

部分更新与钩子

实测 · 本机执行输出
  partial=True 只给 name       → 通过 {'name': 'zed'}
  pre_load 去空格转小写 + post_load 构造对象 → Range ann
  validates 拒绝 admin       → {"name": ["保留名"]}
  validates_schema 跨字段     → {"start": ["start 必须小于等于 end"]}

类型转换

实测 · 本机执行输出
  5        → 5
  '5'      → 5
  '5.0'    错误 Not a valid integer.
  5.0      → 5
  5.5      → 5
  True     错误 Not a valid integer.
  'abc'    错误 Not a valid integer.
  None     错误 Field may not be null.
  ' 7 '    → 7

性能

实测 · 本机执行输出
  marshmallow dump 16.5 ms;手写字典推导 0.7 ms;约 23 倍

分步演示

Marshmallow 序列化
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。marshmallow 4.3.1
    • 没有验证:strict=True 的行为、与 SQLAlchemy 模型集成的 marshmallow-sqlalchemy、自定义字段类型、上下文传参(marshmallow 4 的 context 变化)、与 webargs 的参数解析配合
    京ICP备2026067502号-1京公网安备11010502063487号