Flask 2.x 升级到 3.x 是硬性架构收紧:需 Python ≥3.8 且 Werkzeug ≥3.0.0,request.json 和 flask.json 彻底移除,改用 request.get_json() 和 app.json.provider;_compat 模块删除导致扩展导入失败,SQLAlchemy 等须构造时绑定 app;上下文改用 ContextVar,async 视图必须显式 await,配置类属性立即求值易触发 TypeError。

Flask 2.x 升级到 3.x 不是“改几个函数名”就能完事的,它是一次硬性架构收紧:Python 版本、Werkzeug 依赖、上下文机制、扩展初始化方式全变了。跳过检查直接 pip install flask==3.0.3,90% 的项目会启动失败或运行时出错。
Python 和 Werkzeug 版本必须同步达标
Flask 3.0 要求 Python ≥3.8 且 Werkzeug ≥3.0.0,缺一不可。这不是可选建议,而是安装阶段就会卡住。
- 运行
python --version确认不是 3.7 或更低;如果是,先升级 Python(如用pyenv install 3.11.9),否则pip install flask实际装的仍是 Flask 2.3.3 - 运行
pip show werkzeug,若版本是2.3.9或更低,flask run启动时大概率报ImportError: cannot import name 'url_encode' from 'werkzeug.urls' - 必须执行
pip install "werkzeug>=3.0.0",同时注意markupsafe也要 ≥2.1.0(escape已移入该包)
request.json 和 flask.json 全部失效
Flask 3.x 彻底移除了自动解析和旧 JSON 模块,所有依赖 request.json 或 flask.json 的代码都会出问题。
-
request.json直接访问返回None,必须显式写成request.get_json();若需 Content-Type 校验,加参数force=False并手动检查request.headers.get("Content-Type") -
from flask.json import jsonify→ 改为from flask import jsonify(jsonify已是顶层导出) - 自定义 JSON 序列化逻辑不能继续用
flask.json.JSONEncoder,要迁移到app.json.provider(推荐)或app.json_encoder
扩展初始化和上下文行为彻底重构
很多老扩展在 Flask 3.x 下不是“功能异常”,而是根本导入失败或构造时报错,原因集中在两处:内部模块消失 + 上下文管理换血。
立即学习“Python免费学习笔记(深入)”;
-
ModuleNotFoundError: No module named 'flask._compat':这是 flask-script、flask-migrate 旧版典型错误,_compat模块被物理删除,不能靠降级 Flask 解决,必须升级扩展本身(如flask-migrate>=4.0.0) -
SQLAlchemy(app)取代db = SQLAlchemy(); db.init_app(app):新版本要求构造时绑定 app,否则current_app在异步路由中可能不可用 - 上下文不再走
LocalStack,改用contextvars.ContextVar直接存当前值;这意味着自定义中间件若手动调用push()/pop(),需重写为token = _cv_app.set(ctx)+_cv_app.reset(token)
async 视图不是“开了就快”,而是“错了就崩”
Flask 3.x 默认启用 async,但不会帮你 await。不改业务代码只加 async def,响应体里会出现 <coroutine object at 0x...> 这种字符串。
-
async def api(): return db.query()是错的——如果db.query()返回协程,必须写成return await db.query() -
request.get_json()仍是同步阻塞调用,不能await;别把它和 FastAPI 的request.json()混淆 - WSGI 服务器(如默认 Gunicorn worker)不支持原生 async,必须切到 ASGI(如
uvicorn app:app)或启用gevent,否则 async 路由会退化为同步执行,还多一层调度开销
最易被忽略的是配置类里的表达式:Flask 3.x 在 app.config.from_object(Config) 阶段就立即求值所有属性,os.getenv('MISSING_KEY') or 'default' 若 MISSING_KEY 未设,会直接抛 TypeError: can only concatenate str (not "NoneType") to str,而不是像 2.x 那样延迟到第一次访问才报。


















