目录
三、打包——成exe文件(加入static文件,打包为单个文件)
2、创建一个mysql_config.py(把下面内容复制进去)
4、查看是否自动创建了mysql_config.json文件
视频:
一、配置多个表
1、后端项目改造
2、导包报错——需要修改(2个地方)
3、启动后端(查看是否有问题)
4、配置前端
二、打包——成exe文件(不包含static文件)简单
Static——可在浏览器中运行的静态文件
npm run build 的原理是利用 Vue CLI 的构建工具,
根据项目中配置的各种规则,将源代码转换成可在浏览器中运行的静态文件。
1、后端修改
# main.py绑定静态文件目录
app.mount("/static", StaticFiles(directory='static'), name="static")
system = APIRouter()
@system.get("/")
def index():
return FileResponse(f"static/index.html")
@app.get("/{catchall:path}")
async def catch_all():
return FileResponse(f"static/index.html")
import random
import socket
def get_unused_port():
"""获取未被使用的端口"""
while True:
port = random.randint(1024, 65535) # 端口范围一般为1024-65535
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.bind(("localhost", port))
sock.close()
return port
except OSError:
pass
if __name__ == '__main__':
port = get_unused_port()
import uvicorn
uvicorn.run("__main__:app", reload=False, port=port)
2、前端修改
在打包时,把根路径修改为static
后端请求路径修改
const url = import.meta.env.VITE_BASE_URL + "/Route";
3、运行打包命令
pyinstaller main.py
三、打包——成exe文件(加入static文件,打包为单个文件)
单个文件——并且是客户端(本质上就是用webview去访问网页,看起来就像是客户端一样)
说简单的点:网页套了一个桌面端的壳子
1、后端修改
# main.py绑定静态文件目录 app.mount("/static", StaticFiles(directory='static'), name="static") system = APIRouter() @system.get("/") def index(): return FileResponse(f"static/index.html") @app.get("/{catchall:path}") async def catch_all(): return FileResponse(f"static/index.html") import random import socket import threading import webview import uvicorn def get_unused_port(): """获取未被使用的端口""" while True: port = random.randint(1024, 65535) # 端口范围一般为1024-65535 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.bind(("localhost", port)) sock.close() return port except OSError: pass port = get_unused_port() # 启动FastAPI服务 t = threading.Thread(target=uvicorn.run, args=("__main__:app",), kwargs={"port": port, "reload": False}) t.daemon = True t.start() # 在PyWebview应用程序中加载FastAPI应用程序的URL webview.create_window('Desktop', f'http://localhost:{port}') webview.start()
2、创建build.py(把下面的内容复制进去)
from PyInstaller import __main__ as pyi params = [ '-F', # static目录纳入打包 '--add-data', 'static:static', # 每次打包前清楚build 和 dist目录 '--clean', # 无需用户确认 '--noconfirm', 'main.py' ] pyi.run(params)
3、静态文件路径修改
因为我们要把static文件夹里面的内容打包进去
static_file_abspath = os.path.join(os.path.dirname(__file__), "static") # main.py绑定静态文件目录 app.mount("/static", StaticFiles(directory=static_file_abspath), name="static") system = APIRouter() @system.get("/") def index(): return FileResponse(f"{static_file_abspath}/index.html") @app.get("/{catchall:path}") async def catch_all(): return FileResponse(f"{static_file_abspath}/index.html")
四、动态配置数据库
这里是写死的(打包后就无法修改,那么就不太友好)
1、提取db.py
2、创建一个mysql_config.py(把下面内容复制进去)
# -*- coding: utf-8 -*- # @Author : pan # @Description : 本模块为数据库读取配置 # @Date : 2024年4月30日10:48:01 import json import os from dataclasses import dataclass, asdict @dataclass class MySQLConf: """ MySQL 连接配置信息类 """ host: str = '127.0.0.1' # MySQL 主机地址 port: int = 3306 # MySQL 端口号 user: str = 'root' # MySQL 用户名 password: str = '123456' # MySQL 密码 db: str= 'yolov8' # 数据库名称 charset: str = "utf8" # 字符集,默认为 utf8 def to_dict(self) -> dict: """ 返回配置信息的 JSON 格式表示 Returns: dict: 配置信息的 JSON 格式表示 """ return asdict(self) def read_json_config(self, file_path: str) -> dict: """ 从 JSON 文件中读取配置信息并返回字典 Args: file_path (str): JSON 文件路径 Returns: dict: 包含配置信息的字典 """ # 检查文件是否存在 if not os.path.exists(file_path): # 如果文件不存在,则创建一个包含默认配置信息的 JSON 文件 with open(file_path, "w") as file: json.dump(self.to_dict(), file, indent=4) # 读取配置文件 with open(file_path, "r") as file: config_dict = json.load(file) return config_dict def write_json_config(self, config_dict: dict, file_path: str): """ 将配置信息写入 JSON 文件 Args: config_dict (dict): 包含配置信息的字典 file_path (str): JSON 文件路径 """ with open(file_path, "w") as file: json.dump(config_dict, file, indent=4) # 读取 JSON 文件并将其转换为字典 if __name__ == '__main__': config_dict = MySQLConf().read_json_config("mysql_config.json") # 创建 MySQLConf 实例并解包配置信息 mysql_conf = MySQLConf(**config_dict) # 打印 MySQLConf 的数据 print(mysql_conf.to_dict()) # 修改 MySQLConf 的数据 mysql_conf.password = '123456' # 将字典写入 JSON 文件 MySQLConf().write_json_config(mysql_conf.to_dict(), "mysql_config.json")
3、修改db.py的内容
from sqlmodel import create_engine from mysql_config import MySQLConf config_dict = MySQLConf().read_json_config("mysql_config.json") # 创建 MySQLConf 实例并解包配置信息 mysql_conf = MySQLConf(**config_dict) db_uri = f"mysql+pymysql://" \ f"{mysql_conf.user}:{mysql_conf.password}@" \ f"{mysql_conf.host}:{mysql_conf.port}/{mysql_conf.db}?charset={mysql_conf.charset}" engine = create_engine(db_uri)
4、查看是否自动创建了mysql_config.json文件
五、参考内容(7y)
视频:
文档:
六、个人踩坑点
1、启动参数设置
当我们需要固定端口的时候,直接写死吧,同时要设置好
uvicorn的启动参数if __name__ == '__main__': import uvicorn uvicorn.run("__main__:app", host="0.0.0.0", reload=False, port=5000)
- 使用"__main__:app",而不是"main:app",不然打包后启动会报错。
- 打包前,要把热重载关闭
- 启动端口看情况使用,Fastapi的默认监听端口为5000
- host设置为"0.0.0.0",可以实现对【本地或内网IP+端口】的请求
最后,我们可以把这些参数提取到配置文件,方便我们动态修改
2、跨域设置
# 全部通过 app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )
我们也可以把关于跨域的配置,提取到配置文件,方便我们动态修改
3、数据库连接超时
报错:
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query ([WinError 10053] 你的主机中的软件中止了一个已建立的连接。)')
问题:当Fastapi的后端服务运行后,过一会与数据库的连接会断开
解决方法:
1、设置sqlalchemy 回收链接的时间为10分钟 pool_recycle
engine = create_engine(url, pool_recycle=600)
2、设置每次session操作之前检查 pool_pre_ping
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True,pool_recycle=1800)
3、不使用连接池
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True,pool_recycle=-1)
在SQLAlchemy中,
pool_pre_ping
和pool_recycle
是与数据库连接池管理相关的两个重要参数,用于优化和维护数据库连接的健康状态,避免因长时间未使用导致的连接失效问题。