根本原因是flask打包后template_folder路径失效且模板未被pyinstaller包含:需用sys.executable定位exe目录并显式添加--add-data,同时template_folder必须在flask()初始化时传入。

根本原因不是模板文件没被打包进去,而是 Flask 启动时压根没去你认为它该去的地方找——template_folder 路径在打包后失效了。
Flask 初始化时的 template_folder 是相对路径,但打包后“当前目录”变了
开发时写 app = Flask(__name__, template_folder='./templates'),这个 ./templates 是相对于运行脚本(比如 run.py)的位置。但 PyInstaller 打包成 --onefile 后,exe 解压运行的真实路径是类似 C:\Users\...\AppData\Local\Temp\_MEIxxxxx\ 的临时目录,os.getcwd() 也指向这里,而不是你双击的 exe 所在目录。
- 不要用
os.getcwd() + '/templates'—— 它指向临时解压路径,而你的模板实际跟 exe 在同一级目录 - 正确做法是基于
sys.executable定位 exe 自身位置:os.path.dirname(sys.executable) - 如果用了
--onedir模式,也可以用sys._MEIPASS(仅 PyInstaller),但它只在--onefile下才有效,且值是临时资源根目录,不是 exe 所在目录
PyInstaller 默认不打包 templates/ 和 static/ 目录
PyInstaller 只扫描 Python 字节码依赖,不会自动包含 HTML、CSS、JS 这类非代码文件。即使你写了 template_folder,路径对了也没用——因为那个目录根本不在 exe 解压后的文件系统里。
- 必须显式告诉 PyInstaller 把这些目录加进去:
pyinstaller --add-data="templates;templates" --add-data="static;static" app.py - Windows 下分隔符用
;,Linux/macOS 用: - 目标路径(分号后)必须和你在
Flask(..., template_folder=...)中写的路径一致,否则路径对不上 - 如果你用
spec文件,要确保a.datas列表里包含了对应条目,否则--add-data参数可能被忽略
应用工厂模式下 template_folder 容易被漏掉
很多项目用 create_app() 工厂函数初始化 Flask 实例。这时候很容易把 template_folder 写在 app.config 里,或者在 app = Flask(__name__) 之后再改——这完全无效。
-
template_folder和static_folder是Flask类的构造参数,只在Flask()调用那一刻生效 - 错误写法:
app = Flask(__name__); app.config['TEMPLATE_FOLDER'] = '...' → ❌ 不起作用 - 正确写法:必须在工厂函数内部,
Flask()初始化时就传入:app = Flask(__name__, template_folder=template_path) - 路径构造建议用
pathlib.Path(__file__).parent / 'templates'或os.path.join(os.path.dirname(__file__), 'templates'),避免硬编码
最容易被忽略的一点:路径逻辑和打包模式强耦合。用 --onefile 就得靠 sys.executable 定位;用 --onedir 就可以放心用相对路径,但必须确保 templates/ 确实被复制到了输出目录同级。两者不能混用逻辑,否则一半时间能跑,一半时间报 TemplateNotFound。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











