news 2026/3/4 20:06:35

基于Python的FastAPI后端开发框架如何使用PyInstaller 进行打包与部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Python的FastAPI后端开发框架如何使用PyInstaller 进行打包与部署

一、背景与目标

说明为什么需要将 FastAPI 项目打包为可执行文件。

对比传统部署方式(如 uvicorn main:app)与 PyInstaller 打包方式的区别。

适用场景:企业内网部署、Windows 服务、无 Python 环境的服务器等。

二、环境准备

Python 版本要求(推荐 Python 3.12.4+)。

FastAPI 与依赖(fastapi, uvicorn, pydantic, sqlalchemy, 等)。

安装 PyInstaller:

pip install pyinstaller

三、FastAPI 项目结构示例

展示一个典型的 FastAPI 项目结构:

复制代码

project/

├── app/

│ ├── main.py

│ ├── api/

│ ├── core/

│ ├── models/

│ ├── services/

│ └── __init__.py

├── requirements.txt

复制代码

并说明 main.py 中如何启动服务,例如:

import uvicorn

from app.main import app

if __name__ == "__main__":

uvicorn.run(app, host="0.0.0.0", port=8000)

四、使用 PyInstaller 打包

PyInstaller是目前最流行的Python打包工具之一。它可以将Python脚本打包成独立的可执行文件,支持Windows、Linux和macOS平台。

PyInstaller 有丰富的文档,提供了详细的使用说明和常见问题解答,你可以通过以下链接访问:

PyInstaller 官方文档:https://pyinstaller.readthedocs.io

GitHub 代码库:https://github.com/pyinstaller/pyinstaller

这些文档和资源能帮助你深入了解 PyInstaller 的使用方式,并解决在打包过程中可能遇到的问题。

打包后的可执行文件可以在没有 Python 环境的机器上运行。PyInstaller 会自动分析程序的依赖关系,并将所有必要的库和资源打包到一个文件或者一个文件夹中。

打包过程中,PyInstaller 会生成一个 .spec 文件。这个文件包含了 PyInstaller 的配置信息,其中包含了构建过程的所有配置信息。你可以修改这个文件来定制打包过程。

如果我们执行下面代码

pyinstaller main.py

或者指定更多的参数的代码

pyinstaller --onefile --icon=your_icon.ico main.py

PyInstaller 都会生成一个 .spec 文件,然后可以编辑 main.spec 文件,以便进行更好的控制管理打包文件。

虽然原则上.spec文件支持跨平台的配置,不过我们在实际中往往根据不同的平台配置特定的.spec文件。

你可以手动修改 .spec 文件来添加资源文件、修改导入模块、定制输出路径等。

你可以通过编辑.spec 文件,在EXE、COLLECT和BUNDLE块下添加一个name= ,为PyInstaller提供一个更好的名字,以便为应用程序(和dist 文件夹)使用。

EXE下的名字是可执行文件的名字,BUNDLE下的名字是应用程序包的名字。

复制代码

import sys

import os

from pathlib import Path

# 本文件用于Window平台下打包整个项目,生成一个独立的exe文件,依赖文件松散组合

# 执行命令:pyinstaller main_my.spec

# 打包后生成文件:dist\fastapi_app\fastapi_app.exe

# 运行后,会在当前目录生成一个 dist 文件夹,里面有 fastapi_app.exe 文件,在命令行窗口运行该文件即可启动服务。

if sys.platform == "win32":

icon = "app/images/app.ico"

elif sys.platform == "darwin":

icon = "app/images/app.icns"

block_cipher = None

# 导入 PyInstaller 模块

from PyInstaller.building.build_main import Analysis

from PyInstaller.building.build_main import PYZ

from PyInstaller.building.build_main import EXE

from PyInstaller.building.build_main import COLLECT

# Analysis: PyInstaller Analysis object

a = Analysis(

["app/main.py"],

pathex=[],

binaries=[],

datas=[

("app/uvicorn_config.json", "app"),

("app/.env", "."),

("app/images/*", "app/images"),

("app/templates/*", "app/templates"),

("app/uploadfiles/*", "app/uploadfiles"),

("app/logs/*", "app/logs"),

],

hiddenimports=[

"uvicorn", "fastapi", "pydantic", "aiomysql", 'asyncio', # 确保依赖被正确包含

],

hookspath=[],

hooksconfig={},

runtime_hooks=[],

excludes=[],

win_no_prefer_redirects=False,

win_private_assemblies=False,

cipher=block_cipher,

noarchive=False,

optimize=0,

)

# PYZ: PyInstaller PYZ object

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

复制代码

修改完成后,执行以下命令来重新打包:

pyinstaller main_my.spec

如果我们想在Windows平台生成的dist目录中生成一个启动exe,和其他相关的Lib依赖库目录,那么我们可以适当调整下.spec文件,让它可以生成松散结构的文件目录包。

复制代码

exe = EXE(

pyz,

a.scripts,

[],

exclude_binaries=True,

name="fastapi_app",

debug=False,

bootloader_ignore_signals=False,

strip=False,

upx=True,

upx_exclude=[],

runtime_tmpdir=None,

console=True, # True = 有控制台输出(调试方便),False = 静默运行

onefile=False, # <-- False取消、True使用 onefile 模式

icon=icon, # <-- 图标路径

disable_windowed_traceback=False,

argv_emulation=False,

target_arch=None,

codesign_identity=None,

entitlements_file=None,

)

coll = COLLECT(

exe,

a.binaries,

a.zipfiles,

a.datas,

strip=False,

upx=True,

name='fastapi_app'

)

复制代码

相当于之前在exe包中的a.binaries 和 a.datas从EXE 构造函数中移到了Collect的构造函数里面了。这样会生成下面的目录结构。

image

其中_internal目录包含程序的相关依赖包和文件资源。

image

由于打包的.spec文件指定的目录结构为松散结构(使用了COLLECT构造),那么可以看到 _internal / app目录下有下面的目录结构。

image

也就是我们前面通过 Analysis 模块指定的datas集合路径的内容。

解决常见问题

缺少依赖库:如果打包后运行时出现缺少模块的错误,可以尝试将缺少的模块加入到 hiddenimports 中,或者通过 --hidden-import 选项指定:

大文件:如果使用 --onefile 时打包后的文件太大,考虑使用 --onedir 或通过压缩文件等方法进行优化。

处理资源文件:如果你的应用程序包含非 Python 代码的资源(如图像、配置文件、数据文件等),你需要通过 --add-data 选项指定资源文件的路径,或者在 .spec 文件中修改 datas 选项。

动态链接库,如果你的应用程序依赖于特定的动态链接库(如 DLL 文件或 .so 文件),你需要将这些库包含到打包中。可以在 .spec 文件的 binaries 选项中指定:

多平台支持:PyInstaller 支持 Windows、Linux 和 macOS 等多个平台,但需要在相应的平台上打包。例如,如果你要为 Windows 用户创建可执行文件,最好在 Windows 上运行 PyInstaller 来生成 Windows 的 .exe 文件。如果在 macOS 上打包,生成的文件只能在 macOS 上运行。

在使用 PyInstaller 打包 FastAPI(或其他 Python 应用)时,两个最常见、最容易混淆的参数就是:

--add-data(或 .spec 文件中的 datas)

--hidden-import(或 .spec 文件中的 hiddenimports)

当 PyInstaller 打包时,它默认只会分析 Python 代码的依赖模块,而不会自动包含图片、HTML 模板、配置文件等静态资源。

这时,就需要用 --add-data(或在 .spec 文件的 datas 中定义)告诉它要额外打包哪些文件或目录。

这里不介绍命令行的方式,只介绍.spec 文件写法:

image

PyInstaller 在打包时,会分析你的 Python 源代码(AST)来判断使用了哪些模块。但有些模块是动态导入的(例如通过 importlib 或字符串导入),它就可能漏掉。

解决办法:用 --hidden-import 或者.spec文件中指定 hiddenimports 集合,告诉 PyInstaller 把这些模块也打包进去,如上所示。

总结起来就是:

datas = “我还有额外的文件要带上”。

hiddenimports = “我还有额外的模块要带上”。

五、FastAPI 项目打包的处理

前面介绍了一个简单的fastapi的项目结构和启动,一般我们在开发的时候,启动fastapi,直接调用python解析器运行main.py文件即可启动,常规来说,main.py的启动部分函数代码如下。

复制代码

if __name__ == "__main__":

# 日志配置路径

config_path = resource_path("app/uvicorn_config.json")

# 运行 uvicorn

try:

config = uvicorn.Config(

app = socket_app,

reload=True,

host=settings.SERVER_IP,

log_config = config_config, # 日志配置

)

server = uvicorn.Server(config)

server.run()

except Exception as e:

raise e

复制代码

上面就是我实际项目简化版本的main.py函数的启动内容,正常开发环境,测试是正常的。但是通过pyinstall打包完成,并运行fastapi_app.exe的时候,提示找不到配置文件uvicorn_config.json。

FileNotFoundError: [Errno 2] No such file or directory: 'app/uvicorn_config.json'

这个原因是打包后执行exe文件的当前路径改变了,打包进去的 exe 并没有找到这个文件。首先:修改 .spec 文件,确保文件被打包进去,在 datas 里加这一行 👇

(假设文件路径是 app/uvicorn_config.json)

复制代码

datas = [

("app/uvicorn_config.json", "app"),

("app/templates/*", "app/templates"),

("app/static/*", "app/static"),

("app/images/*", "app/images"),

]

复制代码

这一步确保 exe 中确实包含了你的 uvicorn_config.json 文件。

其次:在 main.py 中使用通用的路径函数resource_path:

复制代码

def resource_path(relative_path: str) -> str:

"""

获取资源文件真实路径,支持:

- 开发模式

- PyInstaller onefile 模式

- PyInstaller COLLECT (_internal) 模式

"""

if hasattr(sys, '_MEIPASS'): # onefile 模式

# exe 解压临时目录

base_path = sys._MEIPASS

else:

# 在松散模式下,_internal 目录才是真正的数据存放处

base_path = os.path.dirname(sys.executable) # exe 所在目录

internal_path = os.path.join(base_path, "_internal")

if os.path.exists(internal_path):# 松散打包目录

base_path = internal_path

else:

# 直接开发运行时

base_path = os.path.abspath(".")

return os.path.join(base_path, relative_path)

复制代码

然后修改你的 uvicorn.Config 代码

替换硬编码路径为:

复制代码

import uvicorn

config_path = resource_path("app/uvicorn_config.json")

config = uvicorn.Config(

app=socket_app,

host=settings.SERVER_IP,

port=settings.SERVER_PORT,

log_config=config_path, # ✅ 动态获取正确路径

)

server = uvicorn.Server(config)

server.run()

复制代码

上面启动后,fastapi 配置文件定位到了,但是可能还会产生新的问题

你可能会发现 app/uvicorn_config.json 里面配置的日志文件路径和实际不对。

image

FileNotFoundError: [Errno 2] No such file or directory: '.../app/logs/log.log'

Uvicorn 在加载 uvicorn_config.json 时的日志路径是 相对进程工作目录,

而不是相对 uvicorn_config.json 文件本身的路径 ——

这正是为什么你配置 "filename": "app/logs/log.log" 仍然报错的根本原因。

我们需要,在运行前动态修正 log_config.json 内部的路径

我们在加载 JSON 后,动态修改其中 "filename" 字段的路径为打包后正确的绝对路径。

修正代码后如下所示。

复制代码

if __name__ == "__main__":

# 动态解析日志配置路径

config_path = resource_path("app/uvicorn_config.json")

# 加载并修改日志配置,主要对日志文件路径进行修正

with open(config_path, "r", encoding="utf-8") as f:

log_config = json.load(f)

# 找到其中的 file handler,改写 filename 为绝对路径

for handler in log_config.get("handlers", {}).values():

if "filename" in handler:

log_file = handler["filename"]

abs_log_path = resource_path(log_file)

os.makedirs(os.path.dirname(abs_log_path), exist_ok=True)

handler["filename"] = abs_log_path # 替换为绝对路径

# 运行 uvicorn(传入已修改的 log_config dict)

try:

config = uvicorn.Config(

app = socket_app,

reload=True,

host=settings.SERVER_IP,

log_config = log_config, # 日志配置,修正方式见上

)

server = uvicorn.Server(config)

server.run()

except Exception as e:

raise e

复制代码

至此,所有问题都顺利解决,能够正常运行起来了,我们来看看FastAPI顺利启动后的效果。复制松散文件夹到服务器上双击运行即可,需要也可以修改配置文件.env实现相关修改。

image

✅ 如果运行打包的exe 提示Missing command.

其实是 uvicorn 的提示,不是 PyInstaller 本身的报错。可能是你的app设置上的问题,你在 main.py 里可能用了这种启动方式:

uvicorn.run("app.main:app", host="0.0.0.0", port=8000)

解决方法 改成直接传入 app 对象,而不是字符串路径:

# ✅ 改成直接传 app 对象

uvicorn.run(app, host="0.0.0.0", port=8000)

这样 uvicorn 就不会去找字符串形式的 module:app,而是直接运行你传进去的 FastAPI 实例。 打包后的 exe 就能正常运行。

✅ 如果提示No module named 'aiomysql'

这个问题其实是 PyInstaller 没有把 aiomysql 打包进去,因为它是动态导入的,PyInstaller 静态分析不到。

方法 A:命令行添加 hidden-import

pyinstaller --onefile --name fastapi_app --hidden-import aiomysql app/main.py

方法 B:在 .spec 文件里加 hiddenimports

找到 .spec 文件里的 Analysis,改成:

复制代码

a = Analysis(

['app/main.py'],

pathex=[],

binaries=[],

datas=datas,

hiddenimports=[

"uvicorn",

"fastapi",

"pydantic",

"aiomysql" # 👈 加上这里

],

hookspath=[],

runtime_hooks=[],

excludes=[],

win_no_prefer_redirects=False,

win_private_assemblies=False,

cipher=block_cipher,

noarchive=False,

)

复制代码

FastAPI + 数据库常用依赖很多(如 sqlalchemy[asyncio]、asyncpg、aiomysql 等),有些也可能被漏掉。做法同样:把缺失的库加到 hidden-import。

复制代码

hiddenimports=[

"uvicorn",

"fastapi",

"pydantic",

"aiomysql",

"asyncpg",

"sqlalchemy.ext.asyncio",

]

复制代码

✅ Data内容的写法

("app/images/*", "app/images")

会把 app/images 下的所有文件 放到 exe 解压后的目录里,路径是 app/images/...

如果代码里是这样写的:

open("app/images/logo.png", "rb")

就能找到,也就是始终保持相对目录的正确性。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/4 10:01:31

毕设 深度学习yolo11森林火灾预警烟雾检测系统(源码+论文)

文章目录 0 前言1 项目运行效果2 课题背景2.1. 森林火灾的全球现状与危害2.2. 传统森林火灾监测技术的局限性2.2.1 人工巡逻监测2.2.2 卫星遥感监测2.2.3 地面传感器网络 2.3. 计算机视觉技术在火灾检测中的应用发展2.4. 本课题的研究价值与创新点2.4.1 理论价值2.4.2 技术创新…

作者头像 李华
网站建设 2026/3/5 2:53:55

31、探索 Linux 安装 DVD-ROM:功能、使用与故障解决

探索 Linux 安装 DVD-ROM:功能、使用与故障解决 1. DVD-ROM 内容概述 DVD-ROM 包含了安装和运行多种 Linux 发行版所需的一切,如 Fedora Core 3、Knoppix 3.6、Linspire 4.5、Mandrake 10.1、SuSE 9.2 和 Xandros 2.5,相当于 11 张 CD-ROM 的内容。主要聚焦于 Fedora Core…

作者头像 李华
网站建设 2026/3/4 7:08:39

Fast GraphRAG终极指南:5分钟快速部署智能知识检索系统

Fast GraphRAG终极指南&#xff1a;5分钟快速部署智能知识检索系统 【免费下载链接】fast-graphrag RAG that intelligently adapts to your use case, data, and queries 项目地址: https://gitcode.com/gh_mirrors/fa/fast-graphrag Fast GraphRAG 是一个革命性的智能…

作者头像 李华
网站建设 2026/3/5 4:03:36

安装网络共享打印机HP1020和epsonLQ590出现0x0000011b错误如何解决?

一台WINDOWS10家庭版的电脑共享了一台惠普HP的激光打印机出来 ,给办公室的其它同事连网使用,只要是WINDOWS7的电脑的同事都能通过网络访问连接安装的方式来进行文件的打印操作,有几台WINDOWS10和WINDOWS11的电脑就是安装不上,在安装上提示windows无法连接到打印机,操作失败…

作者头像 李华
网站建设 2026/3/5 3:16:38

3步搞定Go版本管理:从环境混乱到高效开发的终极指南

3步搞定Go版本管理&#xff1a;从环境混乱到高效开发的终极指南 【免费下载链接】tools [mirror] Go Tools 项目地址: https://gitcode.com/gh_mirrors/too/tools 还在为Go项目版本冲突而苦恼&#xff1f;面对不同项目要求的Go版本&#xff0c;你是否经常手忙脚乱地切换…

作者头像 李华
网站建设 2026/3/5 3:15:28

从零开始掌握Dream-Textures:Blender中的AI材质革命

从零开始掌握Dream-Textures&#xff1a;Blender中的AI材质革命 【免费下载链接】dream-textures Stable Diffusion built-in to Blender 项目地址: https://gitcode.com/gh_mirrors/dr/dream-textures 还在为寻找合适的材质纹理而烦恼吗&#xff1f;Dream-Textures将St…

作者头像 李华