PyInstaller打包Django项目生成exe文件

2024-01-10 05:46:50

背景

用 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目录
在这里插入图片描述

文章来源:https://blog.csdn.net/weixin_41001497/article/details/135402446
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。