Django 项目打包exe本地运行

Django 项目打包exe本地运行

记一次离谱的需求

其实本来觉得Django项目架构比较清晰,代码逻辑也简单,没打算记笔记,结果遇到离谱需求折腾了很久

开发了一个Django项目,到交付的时候了,客户说自己没有服务器…

没服务器还要登录功能😓

没办法,甲方最大,整吧

第一步,迁移数据库

项目数据库是基于服务器上的pgsql,先迁移到本地sqlite

先把数据导出到本地文件
python manage.py dumpdata

理论上是用这个命令,但是我好像报了编码错误,所以编写了下边这个python脚本

import os

from django.core import serializers
from django.apps import apps
import json
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'efplctp.settings')

import subprocess
import sys
import os

# 获取虚拟环境中 Python 解释器的完整路径
# 如果你使用的是 Windows,路径可能是 venv\Scripts\python.exe
# 如果你使用的是 Unix/Linux/macOS,路径可能是 venv/bin/python
python_executable = os.path.join(os.path.dirname(sys.executable), 'python')

# 构造完整的命令
command = [python_executable, "manage.py", "dumpdata"]

# 运行命令并捕获输出
try:
    result = subprocess.run(command, capture_output=True, text=True, encoding="utf-8")
    if result.returncode == 0:
        # 将输出保存到文件
        with open("data.json", "w", encoding="utf-8") as f:
            f.write(result.stdout)
        print("数据已成功导出到 data.json")
    else:
        print("导出数据时出错:", result.stderr)
except Exception as e:
    print("运行命令时发生错误:", e)
修改项目数据库配置

导出了数据库文件,就可以修改setting.py里的数据库配置了,改成

DATABASES = {
    "default": {
        "ENGINE": 'django.db.backends.sqlite3',
        "NAME": BASE_DIR / 'db.sqlite3',
    }
}
创建数据库
python manage.py makemigrations

这个命令是基于模型类代码来检查模型的变化,并生成相应的迁移文件

python manage.py migrate

在数据库中创建相应的表和字段

导入数据

执行以下命令即可

 python manage.py loaddata data.json 

第二步,修改项目配置

修改静态资源文件和模板文件访问路径

大概修改这几个就够了

STATIC_URL = "static/"

STATIC_ROOT = os.path.join(BASE_DIR, "static/")

TEMPLATE_DIRS = [
    os.path.join(BASE_DIR, "templates")
]

DEBUG = False

静态资源文件访问路径重定向

urls.py文件末尾添加代码

urlpatterns += re_path(r'static/(?P<path>.*)$', serve, {'document_root': settings.STATIC_ROOT})

这样就可以在http请求静态资源文件时重定向到本地文件了~

这里要注意,修改的urls.py文件位置!!应该是和setting.py同级,这里有同事给我挖坑,害我折腾好久调不出来

第三步,编写运行脚本

先让项目跑起来

根目录下编写脚本 run.py

def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'efplctp.settings')
    # 手动设置 sys.argv
    sys.argv = ['manage.py', 'runserver', '0.0.0.0:8000', '--noreload']
    with open('log.txt', 'w') as f:
        # 将标准输出重定向到文件对象,
        # 这一步是为了在打包后讲打印输出到这里
        #(其实输出也没什么用,但是不这么写的话,
        # 在打包成运行无命令行窗口的模式
        #( pyi-makespec --onefile --windowed run.py  )时会报错)
        sys.stdout = f
        # 初始化 Django
        django.setup()
        # 执行命令
        execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()

执行命令打包运行脚本

 pyi-makespec --onefile --windowed run.py 

会生成一个spec文件,然后手动修改datas,用于目录映射,修改name指定输出文件名称

运行pyinstaller.exe .\run.spec以生成exe文件,可能会有import报错,哪个模块报错就把哪个模块加到hiddenimports里,最后得到以下run.spec文件

# -*- mode: python ; coding: utf-8 -*-


block_cipher = None


a = Analysis(
    ['run.py'],
    pathex=[],
    binaries=[],
    datas=[('static', './static'),('biz/templates', './templates'),('efplctp/templates', './templates'),('db.sqlite3', './')],
    hiddenimports=[
          "common.middlewares",
          "django.contrib.sessions",
          "biz",
          "django.contrib.staticfiles",
          "django.contrib.contenttypes",
          "common.middlewares",
          "django.contrib.sessions.templatetags",
          'django.templatetags.future',
          'django.templatetags.i18n',
          'django.templatetags.l10n',
          'django.contrib.admin.templatetags.log',
          'django.contrib.admin.templatetags.admin_urls',
          'django.contrib.admin.templatetags.admin_modify',
        ],
    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,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='efplctp',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)

至此打包初步完成

双击运行后自动打开浏览器

run.py文件main方法之前添加以下代码

url = 'http://localhost:8000'
webbrowser.open_new(url)
防止重复运行导致端口占用

run.py文件main方法之前添加以下代码

def kill_process(*pids):
    for pid in pids:
        a = os.kill(pid, signal.SIGILL)
        print('已杀死pid为%s的进程, 返回值是:%s' % (pid, a))


def get_pid(*ports):
    # 其中\"为转义"
    pids = []
    for port in ports:
        str = os.popen("netstat -ano | findstr :%s" % (port)).read()
        tmp = [i for i in str.split(' ') if i != '']
        if len(tmp) > 4:
            pid = tmp[4]
            pids.append(int(pid))
        print(str)
    print(pids)
    return pids


# 杀死占用端口号的ps进程
ps_ports = ["8000"]
kill_process(*get_pid(*ps_ports))
### 如何打包并部署Django项目于Linux环境 #### 准备工作 为了确保Windows开发的Django项目能够在Linux环境中顺利运行,需先在Linux系统内重新创建虚拟环境,并安装依赖项。这一步骤至关重要,因为不同操作系统间可能存在库版本差异或其他兼容性问题。 #### 创建`manage.spec`文件 进入目标Django项目的根目录,在此位置执行命令以生PyInstaller所需的spec模板文件: ```bash pip install pyinstaller pyi-makespec -D manage.py ``` 上述操作会自动生名为`manage.spec`的配置文件[^2]。 #### 修改`.spec`文件 打开刚刚生的`manage.spec`文件,在其中找到`hiddenimports`列表部分,向其添加当前Django项目所使用的全部第三方应用程序名称以及内置应用名(即位于`settings.INSTALLED_APPS`内的条目),以此保证打包过程中不会遗漏任何必要的模块。 #### 文件传输至Linux服务器 完本地准备工作之后,需要把整个Django工程连同新建立的`manage.spec`一同传送到远程Linux主机之上。可借助SCP、SFTP或是直接登录SSH终端使用`rz`指令来进行上传动作;对于已压缩归档过的文件,则可通过简单的下载链接方式获取。 一旦到达目的地后,记得解压档案以便后续处理: ```bash unzip zipped_file.zip ``` #### 构建独立可执行程序 当所有资源都准备就绪时,就可以正式开始构建过程了。切换到包含有`manage.spec`的那个文件夹里边去,接着发出如下指示让PyInstaller按照指定规格来组装最终产物: ```bash pyinstaller manage.spec ``` 功编译完后,会在同一级目录下的`dist/manage/`子文件夹里面发现已经形了一套完整的、可以直接投入生产的Web应用程序副本。 #### 启动服务测试 最后验证一切正常运作无误的话,可以通过下面这条语句启动临时HTTP服务器用于初步检验效果: ```bash ./manage runserver 0.0.0.0:6788 --noreload ``` 此时应该可以在浏览器地址栏键入相应IP加端口号组合访问到预期页面了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gettler•Main

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值