使用PyInstaller打包FastAPI应用时app.mount功能失效求助
FastAPI单文件打包后无法找到static/templates目录的解决方法
问题重现
我的FastAPI应用代码如下:
app = FastAPI() base_dir = os.path.dirname(os.path.abspath(__file__)) static_dir = os.path.join(base_dir, "app/static") templates_dir = os.path.join(base_dir, "app/templates") app.mount("/static", StaticFiles(directory=static_dir), name="static") app.mount("/templates", StaticFiles(directory=templates_dir), name="templates") app.include_router(auths.auth) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
本地用uvicorn、python main.py或fastapi dev运行都正常,但用pyinstaller -F --onefile main.py打包成单文件后,执行exe会报错:
PS C:\Users\Nitish Kumar\abc\cas-apis\dist> .\main.exe Database connection is active. Traceback (most recent call last): File "main.py", line 84, in <module> File "starlette\staticfiles.py", line 59, in __init__ RuntimeError: Directory 'app/static' does not exist [3076] Failed to execute script 'main' due to unhandled exception!
注释掉app.mount相关代码后打包可正常运行,求解决办法。
原因分析
PyInstaller单文件模式(-F/--onefile)会把所有依赖打包成一个exe,运行时自动解压到系统临时目录(比如C:\Users\XXX\AppData\Local\Temp\_MEIXXXXXX\),但app/static和app/templates目录没被包含进打包文件,解压后临时目录里找不到这些文件夹,导致StaticFiles初始化失败。
另外,打包成单文件后,os.path.abspath(__file__)指向的是临时目录里的解压脚本,不是本地源码目录,原来的路径计算逻辑也不适用。
解决方案
步骤1:修改代码适配打包后的路径
区分源码运行和exe运行环境,调整静态文件路径的获取逻辑:
import os import sys from fastapi import FastAPI from fastapi.staticfiles import StaticFiles app = FastAPI() def get_resource_path(relative_path): # 判断是否为打包后的exe环境 if hasattr(sys, '_MEIPASS'): # 打包后资源文件会解压到sys._MEIPASS目录 base_dir = sys._MEIPASS else: # 源码运行时用当前文件所在目录 base_dir = os.path.dirname(os.path.abspath(__file__)) return os.path.join(base_dir, relative_path) # 获取正确的静态文件路径 static_dir = get_resource_path("app/static") templates_dir = get_resource_path("app/templates") app.mount("/static", StaticFiles(directory=static_dir), name="static") app.mount("/templates", StaticFiles(directory=templates_dir), name="templates") app.include_router(auths.auth) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
步骤2:让PyInstaller包含静态文件
有两种方式实现:
方式一:命令行参数直接指定
打包时添加--add-data参数,Windows用分号分隔路径,Linux/macOS用冒号:
# Windows系统 pyinstaller -F --onefile --add-data "app/static;app/static" --add-data "app/templates;app/templates" main.py # Linux/macOS系统 pyinstaller -F --onefile --add-data "app/static:app/static" --add-data "app/templates:app/templates" main.py
方式二:修改spec文件打包
- 先生成spec文件:
pyinstaller -F --onefile main.py
- 打开
main.spec,找到datas字段,添加静态文件映射:
a = Analysis( ['main.py'], # 其他参数保持不变 datas=[('app/static', 'app/static'), ('app/templates', 'app/templates')], # 其他参数保持不变 )
- 用spec文件重新打包:
pyinstaller main.spec
验证
打包完成后运行生成的exe文件,即可正常加载静态文件,不会再出现目录不存在的错误。
内容的提问来源于stack exchange,提问作者Nitish Roy
相关产品推荐
相关产品推荐

