You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyInstaller打包FastAPI后端时SQLite数据库无法打开的问题

解决PyInstaller打包FastAPI后SQLite数据库无法打开的问题

问题背景

使用PyInstaller打包FastAPI后端,已解决依赖问题,但运行可执行文件时出现SQLite数据库无法打开的报错,同时项目依赖基于SQLite的Qdrant向量数据库。

数据库处理代码

from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
from backend.database.models.base import Base

import sys, os

if getattr(sys, 'frozen', False):
    application_path = os.path.dirname(sys.executable)
else:
    application_path = os.path.dirname(os.path.abspath(__file__))

SQLITE_DATABASE_URL = "sqlite:///" + os.path.join(application_path, "backend", "database", "aixplora.db")

class Database:

    def __init__(self):
        self.engine = create_engine(SQLITE_DATABASE_URL, echo=True, connect_args={"check_same_thread": False})
        Base.metadata.create_all(self.engine)
        self.sessionmaker = sessionmaker(autocommit=False, autoflush=False, bind=self.engine)

    def get_session(self):
        return self.sessionmaker()

报错信息

INFO:     127.0.0.1:55980 - "GET /config/ HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "sqlalchemy/engine/base.py", line 145, in __init__
  File "sqlalchemy/engine/base.py", line 3293, in raw_connection
  File "sqlalchemy/pool/base.py", line 452, in connect
  File "sqlalchemy/pool/base.py", line 1268, in _checkout
  File "sqlalchemy/pool/base.py", line 716, in checkout
  File "sqlalchemy/pool/impl.py", line 168, in _do_get
  File "sqlalchemy/util/langhelpers.py", line 147, in __exit__
  File "sqlalchemy/pool/impl.py", line 166, in _do_get
  File "sqlalchemy/pool/base.py", line 393, in _create_connection
  File "sqlalchemy/pool/base.py", line 678, in __init__
  File "sqlalchemy/pool/base.py", line 902, in __connect
  File "sqlalchemy/util/langhelpers.py", line 147, in __exit__
  File "sqlalchemy/pool/base.py", line 898, in __connect
  File "sqlalchemy/engine/create.py", line 637, in connect
  File "sqlalchemy/engine/default.py", line 616, in connect
sqlite3.OperationalError: unable to open database file

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "uvicorn/protocols/http/httptools_impl.py", line 435, in run_asgi
  File "uvicorn/middleware/proxy_headers.py", line 78, in __call__
  File "fastapi/applications.py", line 276, in __call__
  File "starlette/applications.py", line 122, in __call__
  File "starlette/middleware/errors.py", line 184, in __call__
  File "starlette/middleware/errors.py", line 162, in __call__
  File "starlette/middleware/base.py", line 108, in __call__
  File "backend/main.py", line 38, in posthog_middleware
  File "starlette/middleware/base.py", line 84, in call_next
  File "starlette/middleware/base.py", line 70, in coro
  File "starlette/middleware/cors.py", line 83, in __call__
  File "starlette/middleware/exceptions.py", line 79, in __call__
  File "starlette/middleware/exceptions.py", line 68, in __call__
  File "fastapi/middleware/asyncexitstack.py", line 21, in __call__
  File "fastapi/middleware/asyncexitstack.py", line 18, in __call__
  File "starlette/routing.py", line 718, in __call__
  File "starlette/routing.py", line 276, in handle
  File "starlette/routing.py", line 66, in app
  File "fastapi/routing.py", line 237, in app
  File "fastapi/routing.py", line 165, in run_endpoint_function
  File "starlette/concurrency.py", line 41, in run_in_threadpool
  File "anyio/to_thread.py", line 31, in run_sync
  File "anyio/_backends/_asyncio.py", line 937, in run_sync_in_worker_thread
  File "anyio/_backends/_asyncio.py", line 867, in run
  File "backend/main.py", line 70, in get_config
  File "backend/database/database.py", line 21, in __init__
    Base.metadata.create_all(self.engine)
  File "sqlalchemy/sql/schema.py", line 5796, in create_all
  File "sqlalchemy/engine/base.py", line 3243, in _run_ddl_visitor
  File "contextlib.py", line 137, in __enter__
  File "sqlalchemy/engine/base.py", line 3233, in begin
  File "sqlalchemy/engine/base.py", line 3269, in connect
  File "sqlalchemy/engine/base.py", line 147, in __init__
  File "sqlalchemy/engine/base.py", line 2431, in _handle_dbapi_exception_noconnection
  File "sqlalchemy/engine/base.py", line 145, in __init__
  File "sqlalchemy/engine/base.py", line 3293, in raw_connection
  File "sqlalchemy/pool/base.py", line 452, in connect
  File "sqlalchemy/pool/base.py", line 1268, in _checkout
  File "sqlalchemy/pool/base.py", line 716, in checkout
  File "sqlalchemy/pool/impl.py", line 168, in _do_get
  File "sqlalchemy/util/langhelpers.py", line 147, in __exit__
  File "sqlalchemy/pool/impl.py", line 166, in _do_get
  File "sqlalchemy/pool/base.py", line 393, in _create_connection
  File "sqlalchemy/pool/base.py", line 678, in __init__
  File "sqlalchemy/pool/base.py", line 902, in __connect
  File "sqlalchemy/util/langhelpers.py", line 147, in __exit__
  File "sqlalchemy/pool/base.py", line 898, in __connect
  File "sqlalchemy/engine/create.py", line 637, in connect
  File "sqlalchemy/engine/default.py", line 616, in connect
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) unable to open database file

已尝试在spec文件中添加路径:a.datas += Tree('/Users/patrickgerard/Documents/GitHub/aixplora/backend/database/', 'backend/database/'),但问题仍未解决。


解决方案

1. 修正打包后的路径逻辑(核心问题)

如果使用PyInstaller的onefile模式,运行时资源会被解压到临时目录sys._MEIPASS,而非sys.executable所在目录。修改路径获取代码:

if getattr(sys, 'frozen', False):
    # onefile模式优先使用临时资源目录
    application_path = getattr(sys, '_MEIPASS', os.path.dirname(sys.executable))
else:
    application_path = os.path.dirname(os.path.abspath(__file__))

2. 确保数据库目录存在且有写入权限

代码尝试创建数据库文件时,若上级目录不存在会直接报错。提前创建目录:

# 构建数据库目录路径并创建
db_dir = os.path.join(application_path, "backend", "database")
os.makedirs(db_dir, exist_ok=True)
# 拼接数据库文件路径
SQLITE_DATABASE_URL = f"sqlite:///{os.path.join(db_dir, 'aixplora.db')}"

3. 检查spec文件的资源配置

  • 若Tree方式无效,尝试显式指定单个数据库文件:
    a.datas += [('/Users/patrickgerard/Documents/GitHub/aixplora/backend/database/aixplora.db', 'backend/database/aixplora.db')]
    
  • 打包时必须使用该spec文件:
    pyinstaller your_app.spec
    

4. 同步Qdrant的存储路径配置

Qdrant的SQLite存储路径也需要适配打包后的环境,显式指定路径:

from qdrant_client import QdrantClient

# 构建Qdrant存储目录
qdrant_dir = os.path.join(application_path, "qdrant_storage")
os.makedirs(qdrant_dir, exist_ok=True)
# 初始化Qdrant客户端
client = QdrantClient(path=qdrant_dir)

内容的提问来源于stack exchange,提问作者Softwareentwicklung Freelancer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 10:44:54