用 PyInstaller 打包 django 项目,未能在 dist 目录下生成同名文件夹和目标可执行应用程序
报错信息中有大量的 Hidden import “xxx” not found!,但在 spec 文件的 hiddenimports 列表中引入缺失的模块未能解决问题
以下是用 PyInstaller 打包 django 应用的一般步骤
pip install pyinstaller
pyinstaller --name=myproject manage.py #myproject替换为自己的工程名
pyinstaller myproject.spec #myproject替换为自己的工程名
正常情况下,这将在 dist 目录中生成一个包含可执行文件的文件夹,我们需要的打包后的 exe 程序就在这个文件夹中,但是事实上并没有那么顺利。
执行以下命令后,控制台报了很多 Hidden import “xxx” not found! 的告警,而且 dist 目录下也没有生成跟 spec 文件同名的包含可执行文件的文件夹。
pyinstaller myproject.spec
在解决这个问题的过程中,我走了很多弯路。因为网上能查到的资料大部分都是让你在生成的 spec 文件的 hiddenimports=[] 加上这些缺失的模块,提示少了什么就加什么。
我试着先将提供了完整名称的模块加到 hiddenimports 里面
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['manage.py'],
pathex=[],
binaries=[],
datas=[],
#把提示找不到的隐藏模块添加到spec文件中
hiddenimports=[
'channels.templatetags','corsheaders.context_processors','django.contrib.messages.templatetags',
'django.contrib.admin.context_processors','django.contrib.sessions.context_processors',
'channels.context_processors','DeviceManager.templatetags','DeviceManager.context_processors',
'django.contrib.staticfiles.templatetags','django.contrib.contenttypes.context_processors'
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='myproject',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=True,
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,
upx_exclude=[],
name='myproject',
)
修改 spec 配置后,重新执行
pyinstaller myproject.spec
报错又变成了这样
看上去就是分析之后还是找不到模块…… dist 目录下依然没有生成对应的文件夹。
此路不通,但虽然这个方法对我没用,或许对你有用,大家也可以参考一下:pyinstaller系列之七:打包各种问题汇总
最后我发现问题可能出在我没有使用虚拟环境进行隔离,打包的时候就会默认使用全局的 Python 环境,在没有虚拟环境的情况下运行项目可能会有一些潜在的问题,比如我在其它项目中需要安装某些依赖,但跟当前项目所需的依赖发生了冲突。
下面来试试创建一个虚拟环境能否解决问题
python -m venv myvenv #myvenv换成自己的虚拟环境名
可以看到在项目目录下生成了一个 myvenv 文件夹
myvenv\Scripts\activate #myvenv换成自己的虚拟环境名
执行后,命令行变成下面这样,说明已经进入虚拟环境
一定不要忘记,此时虚拟环境下是没有pyinstaller的,之前我们是把它安装在全局python环境下,现在要把它安装在虚拟环境下
pip install pyinstaller
安装后,创建spec文件(如果没有的话)
pyinstaller --name=myproject manage.py #myproject替换为自己的工程名
生成可执行文件
pyinstaller myproject.spec #myproject替换为自己的工程名
当你看到这个,说明打包成功了,dist 目录下也生成了 spec 文件同名的文件夹,可执行程序就在这个文件夹里,且运行程序所需要的依赖都在 _internal 这个文件夹里
说明:
PyInstaller在打包 django 项目的过程中,会通过静态分析来确定 Python 代码的依赖关系,并将这些依赖关系捆绑到生成的可执行文件中。它会分析代码,找到所有导入的模块和依赖项,通过分析导入语句、模块路径和包结构等信息来确定依赖项。它还会查看 Python 解释器的环境,以及在生成 spec 文件时提供的配置选项,来获取更多关于模块位置和依赖项版本的信息。然后将它们打包到最终的可执行文件中,以确保该可执行文件独立运行,不需要系统上安装其他 Python 环境或依赖项。
用命令行运行这个可执行文件(不要直接双击运行,这样如果有错误,窗口会直接消失)
提示缺少 App.asgi 模块
解决方法:
在spec文件中添加以下配置
修改spec文件后,需要重新执行生成命令
pyinstaller myproject.spec
再次启动可执行程序,不再报错