colander验证失败需显式调用e.asdict()获取字段级错误;required=false不影响反序列化,missing=colander.drop才剔除缺失字段;自定义validator必须返回none或raise colander.invalid。

colander 验证失败时默认不报具体字段错误
用 colander.Schema.deserialize() 验证表单数据,如果失败,抛出的是 colander.Invalid 异常,但默认不会直接告诉你哪个字段、为什么错——它只在异常对象的 .asdict() 方法里组织错误信息,而很多老项目直接 str(e) 或没 catch 就返回了 500。
- 必须显式调用
e.asdict()才能得到字段级错误字典,例如{'email': 'Invalid email address.'} - 若用在 Web 框架(如 Pyramid),别依赖框架自动格式化;Pyramid 的
exc_info默认不触发asdict() -
colander.Invalid.msg是顶层错误消息,对嵌套结构基本没用,别试图从中 parse 字段名
required=False + missing=colander.drop 不等于“可选字段”
很多人以为设了 required=False,字段就真的可传可不传,结果发现前端没传该字段,后端反而报 KeyError 或验证跳过——问题出在 missing 和 default 的配合逻辑上。
-
required=False只影响序列化时是否报错,不影响反序列化(即deserialize)时字段是否存在 - 真正控制“字段缺失时怎么处理”的是
missing:设为colander.drop才会从输入字典中彻底剔除该键;设为colander.null或None会保留空值并继续走后续验证 - 常见踩坑:字段类型是
colander.Integer(),又设missing=colander.drop,但没配default,导致后续业务代码访问该字段时报KeyError
自定义 validator 函数里不能 raise Exception
写 colander.Function 或给字段加 validator= 参数时,习惯性用 raise ValueError('xxx'),结果验证失败却静默通过或抛出未捕获异常——colander 要求 validator 必须严格返回 None 表示通过,否则必须 raise colander.Invalid 实例。
- 错误写法:
lambda node, value: raise ValueError('too long')→ 触发未处理异常,中断整个验证流程 - 正确写法:
lambda node, value: None if len(value) - 注意
node是字段节点对象,不是字符串名;传错node会导致错误信息里字段路径为空或错乱
colander.MappingSchema 对 null 输入的容忍度极低
前端偶尔发来 null(JSON 中的 null,Python 中是 None),而 schema 是 colander.MappingSchema,结果直接炸出 TypeError: argument of type 'NoneType' is not iterable ——这不是 bug,是设计使然:MappingSchema 默认不接受 None 作为输入值。
立即学习“Python免费学习笔记(深入)”;
- 解决方式只有两个:要么在调用
deserialize()前预检输入是否为None,要么给 schema 显式加typ=colander.Mapping(allow_empty=True)(注意:allow_empty控制的是空 dict,不是None) - 更稳妥的做法是包装一层:如果原始数据是
None,先转成空字典{}再进deserialize - 这个行为和
colander.SequenceSchema一致,但容易被忽略,因为多数文档示例都从非空字典开始










