为何必须执行session.commit()才能正确处理DateTime数据?
问题解析:DateTime字段需Commit才能正常序列化的原因
核心原因
commit前后,start_time字段的数据类型不一致:
- 未commit时:你给
start_time赋值的是字符串"2022-08-18T17:18:00.000Z",此时这个值还停留在Python模型对象的属性里,没有经过SQLAlchemy/psycopg2的类型转换,依然是字符串类型。 - commit后:SQLAlchemy会把这个字符串传递给psycopg2,数据库驱动会自动将符合格式的时间字符串转换为Python的
datetime.datetime对象,并存回模型实例的start_time属性中。
而toastedmarshmallow.Jit序列化器在处理DateTime类型字段时,只接受datetime对象,无法直接处理字符串,所以未commit时会抛出格式化错误;而id(整数)、string_data(字符串)的类型和字段定义完全匹配,不需要额外转换,因此序列化正常。
细节补充
- SQLAlchemy的类型转换时机:SQLAlchemy不会在你给模型属性赋值时立即做类型转换,而是在flush/commit阶段才会将数据传递给数据库驱动,由驱动完成字符串到datetime对象的转换,之后会把转换后的对象同步回模型实例。
- toasted-marshmallow的限制:为了追求性能,toasted-marshmallow的JIT序列化器对类型检查更严格,不会自动尝试将字符串解析为datetime对象,必须传入符合字段类型的原生对象。
解决方案(无需Commit即可正常序列化)
手动将时间字符串转换为datetime对象后再赋值:
from datetime import datetime # 将ISO格式字符串转为带时区的datetime对象 time_obj = datetime.fromisoformat("2022-08-18T17:18:00.000Z".replace("Z", "+00:00")) time = TheTime(id=3, start_time=time_obj, string_data="Hello, World!") session.add(time) # 无需commit,直接序列化即可正常输出 time_schema = TheTimeSchema() dump_data = time_schema.dump(time) print(dump_data)
内容的提问来源于stack exchange,提问作者Eric G
相关产品推荐
相关产品推荐

