必须重写JSONEncoder或JSONProvider,因Flask默认序列化不支持datetime;推荐Flask≥2.2使用自定义JSONProvider,统一处理datetime为isoformat()字符串,避免手动转换。

Flask默认JSON序列化不支持datetime怎么办
Flask内置的jsonify()和json.dumps()底层用的是Python标准库json模块,它不认识datetime、date、Decimal这类类型,直接序列化会抛出TypeError: Object of type datetime is not JSON serializable。
最直接的解法不是每次手动调strftime(),而是统一接管JSON编码逻辑。Flask提供了app.json_encoder(Flask 2.2+)或老版本的app.json_encoder继承机制,优先推荐前者。
- Flask ≥ 2.2:直接赋值自定义
JSONProvider子类,更灵活也更符合未来方向 - Flask flask.json.JSONEncoder并重写
default()方法 - 别在视图里用
json.dumps(obj, default=...)临时处理——容易漏、难维护、绕过Flask的响应头设置
用Flask 2.2+的JSONProvider定制日期格式
新版Flask把JSON编解码抽象成JSONProvider接口,你可以继承DefaultJSONProvider并覆盖default()。关键点是:必须显式调用super().default()兜底,否则基础类型(如None、list)会失效。
from flask import Flask
from flask.json.provider import DefaultJSONProvider
from datetime import datetime, date
import decimal
<p>class CustomJSONProvider(DefaultJSONProvider):
def default(self, obj):
if isinstance(obj, datetime):
return obj.strftime('%Y-%m-%d %H:%M:%S')
if isinstance(obj, date):
return obj.isoformat()
if isinstance(obj, decimal.Decimal):
return float(obj)
return super().default(obj) # ← 这行不能少</p><p>app = Flask(<strong>name</strong>)
app.json = CustomJSONProvider(app)
- 时间格式按需调整:
strftime()比isoformat()更可控,比如要带毫秒就用%Y-%m-%d %H:%M:%S.%f - 避免用
str(obj)泛化转换——datetime转成字符串后前端解析易出错,明确格式才可靠 - 如果项目还用了SQLAlchemy,注意
datetime字段从ORM查出来就是原生类型,无需额外转换
Flask旧版本(
老版本靠app.json_encoder = MyEncoder,但要注意:这个赋值必须在Flask(__name__)之后、任何路由注册之前完成,否则部分内部初始化可能已固化默认编码器。
立即学习“Python免费学习笔记(深入)”;
from flask import Flask, jsonify from flask.json import JSONEncoder from datetime import datetime <p>class MyJSONEncoder(JSONEncoder): def default(self, obj): if isinstance(obj, datetime): return obj.isoformat() + 'Z' # 显式标注UTC return super().default(obj)</p><p>app = Flask(<strong>name</strong>) app.json_encoder = MyJSONEncoder # ← 必须放这里,不能晚于路由定义
-
jsonify()会走这个编码器,但render_template()或手动json.dumps()不会——后者仍需单独传cls=MyJSONEncoder - 如果用了
flask-restful等扩展,它们可能有自己的JSON处理链,得看具体扩展文档是否兼容app.json_encoder - 某些部署环境(如Gunicorn + uWSGI)可能缓存了应用实例,修改编码器后务必重启worker
时区处理和Decimal精度丢失问题
日期转字符串本身不解决时区问题,datetime对象带时区(tzinfo)时,isoformat()会包含偏移量,但strftime()默认丢掉。Decimal转float则可能损失精度——这两点线上最容易被忽略。
- 带时区的
datetime建议先转为UTC再序列化:obj.astimezone(timezone.utc).strftime(...) - Decimal若需高精度,考虑转为字符串:
str(obj),前端用BigInt或专门解析,但需前后端约定 - 别依赖
datetime.__str__()或repr()——输出格式不稳定,且含调试信息(如datetime.datetime(...))
真正麻烦的不是怎么写编码器,而是确保所有数据出口(API响应、日志JSON化、缓存序列化)都走同一套规则。一旦有分支路径绕过它,问题就会零星出现,很难复现。


















