PyInstaller打包Django项目生成exe文件
背景
用 PyInstaller 打包 django 项目,未能在 dist 目录下生成同名文件夹和目标可执行应用程序
报错信息中有大量的 Hidden import “xxx” not found!,但在 spec 文件的 hiddenimports 列表中引入缺失的模块未能解决问题
以下是用 PyInstaller 打包 django 应用的一般步骤
安装PyInstaller
pip install pyinstaller
创建PyInstaller spec文件
pyinstaller --name=myproject manage.py #myproject替换为自己的工程名
运行PyInstaller:
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
再次启动可执行程序,不再报错
但是当我启动nginx服务,用浏览器访问页面的时候,却提示找不到模板文件
想起有一个告警被我忽略了
这个static目录本来是在django项目根目录下的,怎么变成去_internal目录下了?
原因:
使用 PyInstaller 打包 Django 项目时,生成的可执行文件在运行时会将工作目录切换到 _internal 目录,这是 PyInstaller 为了确保捆绑资源和模块时的一种策略。
默认情况下,PyInstaller 将可执行文件所在目录作为工作目录,但是在内部执行时,它可能会将工作目录更改为 _internal 目录,以确保它可以访问其中捆绑的资源。
也就是说,浏览器输入 url,向 django 服务端请求对应的模板文件的时候,它把 E:\Demo\项目名称\dist\myproject_internal 当做 BASE_DIR 了,然后根据STATICFILES_DIRS的配置,到这个目录的static和static/static路径下去寻找模板文件和资源文件,找不到就会报错。
解决方法:
修改spec文件
a = Analysis(
['manage.py'],
pathex=['E:/Demo/工程名称'], #指定项目根目录
binaries=[('static', 'static')], #这里第一个static是相对pathex指定的路径的,也就是E:/Demo/工程名称/static的意思,也可以直接写绝对路径E:/Demo/工程名称/static
datas=[],
hiddenimports=['App.asgi'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
)
根据spec重新生成可执行文件,告警消失
并且在_internal文件夹下生成了一个static目录
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!