SQLite 本地有表,部署后却报 no such table:核对实际数据库路径
SQLite 本地能查、部署后报 no such table 时,在失败连接核对完整数据库路径,区分 Django 配置和独立 sqlite3 连接,防止相对路径隐式创建空库。
SQLite 数据库在本地能查询,部署到 Web 服务后却报 sqlite3.OperationalError: no such table。运行迁移或修改 Django settings 后仍失败时,先查看真正抛错的连接打开了哪个文件。一个相对路径可能随进程工作目录变化,指向另一个数据库,甚至悄悄创建了空库。
本文针对 Python sqlite3 或 Django 使用文件数据库的场景。缺表也可能因为迁移没执行、查询表名不对或使用了其他数据库别名;没有核对路径前,不能认定只有相对路径这一种原因。
用失败的那条连接查看文件
在发生问题的连接上执行下面的只读检查示例,不要另建一个“看起来相同”的连接代替它:
PRAGMA database_list;
SELECT name FROM main.sqlite_master WHERE type = 'table';
database_list 的第三列给出当前数据库文件路径;空路径可能对应内存等非文件数据库,需要继续核对连接方式。表列表检查的是 main 库,若应用使用 ATTACH 或其他库,应检查对应 schema。
如果实际使用 SQLAlchemy 的 :memory: 数据库,建表后只有 TestClient 请求报 no such table,应另查内存数据库是否跨连接共享,不能套用文件路径的修复办法。
将这条连接的路径与本地可用文件、部署文件、迁移命令所用文件逐一比较。文件名相同不够,完整路径才有判断价值。Web 进程、控制台和计划任务的工作目录可能不同,sqlite3.connect("app.db") 不会自动以 Python 文件所在目录为基准。
若路径正确却没有目标表,再核对应用选择的数据库别名、表名与迁移状态。不要在每次请求中创建表来掩盖错误,也不要把另一个环境的库直接覆盖上来。
Django settings 改了,独立 sqlite3 连接可能没改
Django 的 SQLite DATABASES 配置应指向明确的完整文件路径。下面是配置片段示例,BASE_DIR 需已经是项目按部署规则确定的绝对目录;保留项目其他配置:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "app.db",
}
}
如果某个 view 或后台任务又自己调用 sqlite3.connect("app.db"),它不会自动继承 Django 的 NAME。改 settings 和执行 Django 迁移,也不会改变这条独立连接。需要让各入口使用同一份明确路径,或按项目设计使用 Django 已管理的连接。
同时确认迁移使用的是同一套 settings、同一个数据库别名与同一部署目录。路径修正后重新加载相应应用进程,避免旧连接继续持有原文件;按现有服务流程操作,记录旧路径以便回退。
不允许自动创建时,让错误在连接阶段出现
Python sqlite3 默认可在数据库文件不存在时创建新文件,因此“连接成功”不能证明打开的是已有业务库。对于必须使用已有库的独立连接,可以采用 URI 的 mode=rw,让不存在的路径直接失败。
下面是类 Unix 路径的示例,应换成已经确认的绝对文件 URI;URI 中的特殊字符须按规则编码,Windows 路径格式也需相应调整:
import sqlite3
con = sqlite3.connect("file:/srv/app/data/app.db?mode=rw", uri=True)
mode=rw 允许读写,但不创建新数据库。这项措施能更早暴露路径错误,不能补出缺失的表,也不会代替文件和目录权限检查。不能把它用在原本就需要首次初始化数据库的流程中。
调整前备份真正的业务库,停止涉及该文件的写入后按应用支持的方式备份或迁移。意外生成的小数据库先保留并确认是否含数据,不凭文件大小直接删除;WAL 模式下也不要只搬一个主文件而丢掉尚未合并的日志。
验收时,从实际 Web 请求、后台任务和迁移入口分别确认路径与库别名,目标表存在,原查询能够完成;只有其中一个终端查到了表,还不足以说明部署已经使用正确数据库。


