




sqlite数据库默认不启用外键约束,即使表结构中定义了 foreign key,删除被引用的父记录也不会报错;需显式执行 pragma foreign_keys = on 才能激活完整性检查。
在使用 SQLAlchemy 与 SQLite 开发时,你可能会遇到一个看似矛盾的现象:数据库表已正确定义外键(如 Toot.list_id 引用 MastoList.id),但在 Python 代码中调用 session.delete() 删除父记录后,程序成功提交,且子表数据未被级联处理或报错——而直接通过 DB Browser for SQLite 执行相同删除操作却立即触发 FOREIGN KEY constraint failed 错误。
根本原因在于:SQLite 默认禁用外键支持。尽管 CREATE TABLE 语句中包含 FOREIGN KEY(...) 定义,SQLite 仅将其视为注释性声明,不会主动验证约束,除非显式启用。
✅ 正确做法是在应用初始化阶段(如创建引擎时)启用外键:
from sqlalchemy import create_engine
# 启用外键并确保连接时生效
engine = create_engine(
"sqlite:///app.db",
echo=True,
connect_args={"check_same_thread": False}
)
# 在每个新连接上启用外键(推荐方式)
with engine.connect() as conn:
conn.execute(text("PRAGMA foreign_keys = ON"))
conn.commit()更稳健的方式是使用 connect_args 配合事件监听器,确保所有连接自动启用:
from sqlalchemy import event
from sqlalchemy.engine import Engine
@event.listens_for(Engine, "connect")
def set_sqlite_pragma(dbapi_connection, connection_record):
cursor = dbapi_connection.cursor()
cursor.execute("PRAGMA foreign_keys = ON")
cursor.close()⚠️ 注意事项:
? 验证是否生效:
可在任意连接中执行以下查询确认:
with engine.connect() as conn:
result = conn.execute(text("PRAGMA foreign_keys")).scalar()
print("Foreign keys enabled:", result) # 应输出 1✅ 总结:
要真正保障参照完整性,必须 双管齐下:
二者缺一不可——前者兜底防脏数据,后者提升开发体验与语义清晰度。