如何让Marshmallow在序列化时抛出AttributeError及缺失属性异常?
解决Marshmallow序列化时缺少required字段不报错的问题
你遇到的这个情况其实是Marshmallow的默认行为:required=True参数只在反序列化(从字典/JSON转成对象)时生效,序列化(从对象转成JSON)时,框架只会尝试读取对象的属性,如果属性不存在就直接跳过该字段,不会主动抛出异常。这就是为什么你调用Foo().dumps(bar)返回空JSON,但直接访问bar.bar会触发AttributeError的原因。
要实现序列化时缺少必填字段就抛出异常,有几种实用的方法:
方法一:用post_dump钩子校验序列化结果
在Schema里添加post_dump装饰器,序列化完成后检查必填字段是否存在,不存在就抛出ValidationError:
import marshmallow from marshmallow.decorators import post_dump class Foo(marshmallow.Schema): bar = marshmallow.fields.Str(required=True) @post_dump def enforce_required_fields(self, serialized_data, **kwargs): # 检查所有required=True的字段是否都在序列化结果里 for field_name, field in self.fields.items(): if field.required and field_name not in serialized_data: raise marshmallow.ValidationError(f"Missing required field: {field_name}") return serialized_data class Bar: pass bar = Bar() # 现在执行这行代码会抛出ValidationError Foo().dumps(bar)
这个方法的好处是可以一次性校验所有必填字段,不用逐个字段处理。
方法二:自定义严格校验的字段
如果只想针对特定字段做严格校验,可以自定义字段类,重写_serialize方法,在读取属性时捕获AttributeError并转为Marshmallow的校验异常:
import marshmallow class StrictRequiredStr(marshmallow.fields.Str): def _serialize(self, value, attr_name, obj, **kwargs): try: # 主动尝试获取对象属性,不存在则抛出AttributeError value = getattr(obj, attr_name) except AttributeError as e: # 转为Marshmallow的ValidationError,保持异常风格统一 raise marshmallow.ValidationError(f"Required field '{attr_name}' is missing from object") from e # 调用父类的序列化逻辑处理正常情况 return super()._serialize(value, attr_name, obj, **kwargs) class Foo(marshmallow.Schema): # 使用自定义的严格字段 bar = StrictRequiredStr(required=True) class Bar: pass bar = Bar() # 执行后会抛出ValidationError Foo().dumps(bar)
方法三:重写Schema的dump方法
如果你想让整个Schema的序列化都强制校验必填字段,可以重写Schema的dump方法,在序列化前先检查对象的属性:
import marshmallow class StrictSchema(marshmallow.Schema): def dump(self, obj, **kwargs): # 遍历所有required=True的字段,检查对象是否有对应属性 for field_name, field in self.fields.items(): if field.required and not hasattr(obj, field_name): raise marshmallow.ValidationError(f"Object missing required attribute: {field_name}") return super().dump(obj, **kwargs) # 继承自定义的StrictSchema class Foo(StrictSchema): bar = marshmallow.fields.Str(required=True) class Bar: pass bar = Bar() # 执行后抛出ValidationError Foo().dumps(bar)
这个方法适合你有多个Schema都需要严格校验的场景,只需要继承StrictSchema即可,不用重复写校验逻辑。
内容的提问来源于stack exchange,提问作者Kimvais
相关产品推荐
相关产品推荐

