Marshmallow Schema数据类加载时datetime字段验证失败问题
我用marshmallow_dataclass定义了遵循Marshmallow Schema的数据类,代码如下:
from marshmallow_dataclass import dataclass import datetime from typing import ClassVar, Type import marshmallow class BaseClass: Schema: ClassVar[Type[marshmallow.Schema]] = marshmallow.Schema # 类型检查用 @dataclass class Test(BaseClass): time: datetime.datetime
遇到的问题是两种加载数据类的方式表现不一致,原本预期以下两种方式效果相同:
inp = {"time":datetime.datetime.now()} method1 = Test(**inp) # 正常运行 method2 = Test.Schema().load(inp) # >>> marshmallow.exceptions.ValidationError: {'time': ['Not a valid datetime.']}
其他类型下两种加载方式表现一致,但datetime类型会触发验证异常,请问这是什么原因?
原因分析
两种加载逻辑本质不同
Test(**inp)是直接调用Python数据类的构造方法,Python原生支持datetime.datetime类型作为参数,无需额外转换,因此能正常运行。而Test.Schema().load(inp)走的是Marshmallow的验证反序列化流程,Marshmallow的DateTime字段默认只接受字符串格式的时间(如"2024-05-20T12:00:00"),而非直接的datetime对象。BaseClass的Schema定义覆盖了自动生成规则
你在BaseClass中手动指定了Schema = marshmallow.Schema,这会覆盖marshmallow_dataclass自动生成的带字段类型映射的Schema。原本marshmallow_dataclass会为datetime.datetime类型自动绑定对应的Marshmallow字段规则,但现在继承的是基础Schema,没有正确配置字段反序列化逻辑,导致传入datetime对象时触发验证错误。
解决方法
去掉BaseClass中手动定义的Schema类变量,让marshmallow_dataclass自动生成正确的Schema:
from marshmallow_dataclass import dataclass import datetime from typing import ClassVar, Type import marshmallow class BaseClass: # 移除手动指定的Schema定义 pass @dataclass class Test(BaseClass): time: datetime.datetime
如果需要保留类型提示,可仅声明类型不赋值:
from marshmallow_dataclass import dataclass import datetime from typing import ClassVar, Type import marshmallow class BaseClass: Schema: ClassVar[Type[marshmallow.Schema]] # 仅做类型提示,不赋值 @dataclass class Test(BaseClass): time: datetime.datetime
修改后,Test.Schema().load(inp)就能正确处理datetime.datetime对象,因为自动生成的Schema会正确识别字段类型并应用对应反序列化逻辑。
内容的提问来源于stack exchange,提问作者Steinn Hauser Magnússon

