Marshmallow (Flask-Marshmallow) 使用指南
Marshmallow (Flask-Marshmallow) 使用指南
本文档总结了本项目中使用 flask-marshmallow (简称 ma) 进行对象序列化(Serialization)和反序列化(Deserialization)的规范与技巧。
1. 注册与初始化 (Registration)
在本项目中,ma 对象在 app/extensions.py 中被定义,并在 app/__init__.py 中通过 init_app 模式初始化。
app/extensions.py:
from flask_marshmallow import Marshmallowma = Marshmallow()# ...其他扩展app/init.py:
from app.extensions import ma
def create_app(config_name): # ... ma.init_app(app) # ...2. 与 SQLAlchemy 集成 (Model Integration)
我们通常使用 ma.SQLAlchemyAutoSchema 来自动生成基于 SQLAlchemy 模型的 Schema。这能极大减少重复代码。
基础结构
from app.extensions import ma, dbfrom .models import User
class UserSchema(ma.SQLAlchemyAutoSchema): class Meta: model = User # 绑定的 SQLAlchemy 模型 load_instance = True # load() 时自动反序列化为 Model 实例 sqla_session = db.session # 必须指定 session 才能 load3. 字段控制 (Fields Control) - 核心内容
这是最容易混淆的部分。Marshmallow 提供了两种主要模式来控制输出字段,特别是处理 下划线命名 (snake_case) 到 驼峰命名 (camelCase) 的转换。
模式 A:自动模式 + 局部重写 (Implicit Mode)
适用场景:希望输出 Model 的所有字段,且只针对部分字段改名或格式化。
特点:
- 不写
fields = (...)。 - Marshmallow 默认会包含 Model 的所有字段。
- 使用
ma.auto_field(data_key='...')来重写特定字段的输出键名。
示例:
class RoleSchema(ma.SQLAlchemyAutoSchema): class Meta: model = Roles load_instance = True # 不需要写 fields,默认全包含
# 1. 重写 role_name 字段,输出为 roleName role_name = ma.auto_field(data_key='roleName')
# 2. 没写的字段(如 id, note)会自动原样输出模式 B:显式白名单模式 (Explicit Mode)
适用场景:字段名和 Model 不一致,或者需要严格控制输出字段(例如隐藏密码)。
特点:
- 必须写
fields = ('field1', 'field2', ...)。 - 只有在
fields列表里的字段才会被输出。 - 注意:如果通过
auto_field重写了字段名,fields里要写Schema 中定义的变量名。
示例 (UserSchema):
class UserSchema(ma.SQLAlchemyAutoSchema): class Meta: model = Users # 必须写 fields,否则可能会出现重复字段(如 user_id 和 userId 同时出现) fields = ('userId', 'inDate', 'enable')
# 1. 变量名 userId (新) vs Model 属性 user_id (旧) # 因为名字不一致,Marshmallow 不会自动关联,必须明确指定 attribute='user_id' 或第一个参数 userId = ma.auto_field('user_id', data_key='userId')
# 2. 格式化日期 inDate = ma.Function(lambda obj: obj.in_date.strftime('%Y-%m-%d'))
# 3. 自定义逻辑 enable = ma.Function(lambda obj: 1 if obj.enable == '1' else 0)模式转化对比
目标:把数据库的 user_name 输出为前端的 userName。
| 模式 | 写法 | 优点 | 缺点 |
|---|---|---|---|
| 自动模式 | user_name = ma.auto_field(data_key='userName')(Meta 中不写 fields) | 简单,自动包含其他字段 | 变量名必须是 user_name (下划线),不符合某些 Python 纯驼峰代码风格 |
| 显式模式 | userName = ma.auto_field('user_name', data_key='userName')(Meta 中写 fields=('userName', ...)) | 变量名可以是 userName,符合驼峰风格 | 比较繁琐,必须手动维护 fields 列表,否则字段会丢或重 |
本项目推荐:
- 如果只是简单改名,推荐 自动模式(变量名保持下划线,用
data_key改输出名)。 - 如果涉及复杂逻辑或安全性(如
UserSchema),推荐 显式模式。
4. Meta 选项详解
在 class Meta 中,常用的配置项如下:
| 选项 | 说明 | 示例值 |
|---|---|---|
model | 绑定的 SQLAlchemy 模型类 | Users |
load_instance | 反序列化时是否创建模型实例 | True (推荐), False (只返回字典) |
sqla_session | 数据库会话,用于查询和反序列化 | db.session |
fields | 白名单:只允许这些字段输出 | ('id', 'name', 'createTime') |
exclude | 黑名单:排除这些字段 | ('password', 'secret_key') |
dateformat | 默认日期格式字符串 | '%Y-%m-%d' |
datetimeformat | 默认时间格式字符串 | '%Y-%m-%d %H:%M:%S' |
unknown | 处理未知字段的行为 | EXCLUDE (忽略), INCLUDE, RAISE (报错) |
5. 常用方法与使用 (Usage)
初始化 Schema
# 处理单个对象user_schema = UserSchema()
# 处理对象列表 (List)users_schema = UserSchema(many=True)序列化 (Serialization)
Model -> Dict/JSON
user = Users.query.first()
# Dump 单个result = user_schema.dump(user)# result: {'userId': 1, 'userName': 'admin'}
# Dump 列表users = Users.query.all()results = users_schema.dump(users)# results: [{'userId': 1...}, {'userId': 2...}]反序列化 (Deserialization)
Dict/JSON -> Model
data = {'userName': 'new_user', 'password': '123'}
try: # Load 会自动进行验证 (Validate) 和转换 # 如果 Meta 中 load_instance=True,这就返回一个 Users 对象 new_user = user_schema.load(data)
db.session.add(new_user) db.session.commit()except ma.ValidationError as err: print(err.messages) # 验证失败信息仅验证 (Validation Only)
如果不希望创建对象,只想检查数据格式:
errors = user_schema.validate(data)if errors: print("数据校验失败:", errors)