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

Peewee操作SQLite触发FOREIGN KEY constraint failed错误的原因与解决

补充更新

我使用DB Browser图形客户端查看表结构时发现,初始代码生成的candles表中timeframe_id和symbol_id字段为INTEGER类型,而非sqlite3客户端执行.schema命令输出的VARCHAR类型:

sqlite> .schema candles
CREATE TABLE IF NOT EXISTS "candles" ("id" INTEGER NOT NULL PRIMARY KEY, "timeframe_id" VARCHAR(255) NOT NULL, "symbol_id" VARCHAR(255) NOT NULL, "text" VARCHAR(255) NOT NULL, FOREIGN KEY ("timeframe_id") REFERENCES "timeframes" ("name"), FOREIGN KEY ("symbol_id") REFERENCES "symbols" ("name"));
CREATE INDEX "candles_timeframe_id" ON "candles" ("timeframe_id");
CREATE INDEX "candles_symbol_id" ON "candles" ("symbol_id");
sqlite>

发现该问题后,我补充学习了外键相关知识,同时梳理了peewee的外键实现逻辑,明确了之前对外键概念的认知误区,也读懂了官方文档的相关说明。

以下是修改后可正常运行的代码:

from collections import namedtuple
from peewee import *
from playhouse.sqlite_ext import SqliteExtDatabase

db = SqliteExtDatabase('test.db', pragmas={'foreign_keys': 1, 'journal_mode': 'wal'})

class BaseModel(Model):
        class Meta:
            database = db

class Symbols(BaseModel):
    name = CharField(unique=True)

class Timeframes(BaseModel):
    name = CharField(unique=True)

class Candles(BaseModel):
    timeframe = ForeignKeyField(Timeframes, field='name') 
    symbol = ForeignKeyField(Symbols, field='name')

db.create_tables([Symbols, Timeframes, Candles])

Symbols.insert(name='ABC').on_conflict(action='IGNORE').execute()
Timeframes.insert(name='1m').on_conflict(action='IGNORE').execute()
print(f"symbols: {Symbols.select().dicts().get()}")
print(f"timeframes: {Timeframes.select().dicts().get()}")
try:
    Candles.insert(timeframe = '1m', symbol = 'ABC').execute()
except Exception as e:
    print(f"Exception: {e}")
print(f"candles: {Candles.select().dicts().get()}")

运行结果:

% test.py
symbols: {'id': 1, 'name': 'ABC'}
timeframes: {'id': 1, 'name': '1m'}
candles: {'id': 1, 'timeframe': '1m', 'symbol': 'ABC'}
%
原问题

我尝试通过peewee向sqlite表插入带外键字段的数据,持续触发FOREIGN KEY constraint failed报错,但不清楚问题根源。

我是数据库开发新手,按照外键的基础概念,只要Candles.symbol和Candles.timeframe的值在父表Symbols.name和Timeframes.name中已经存在,就应该可以正常插入。

外键约束可以防止无效数据插入外键列,因为外键值必须是父表对应列中已有的值。

我在示例代码中添加了日志确认预期的数值均已存在,依然报错,希望获得相关指导。

报错代码如下:

from peewee import *
from playhouse.sqlite_ext import SqliteExtDatabase

db = SqliteExtDatabase('test.db', pragmas={'foreign_keys': 1, 'journal_mode': 'wal'})

class BaseModel(Model):
        class Meta:
            database = db

class Symbols(BaseModel):
    name = CharField(unique=True)

class Timeframes(BaseModel):
    name = CharField(unique=True)

class Candles(BaseModel):
    timeframe = ForeignKeyField(Timeframes) 
    symbol = ForeignKeyField(Symbols)

db.create_tables([Symbols, Timeframes, Candles])

Symbols.insert(name='ABC').on_conflict(action='IGNORE').execute()
Timeframes.insert(name='1m').on_conflict(action='IGNORE').execute()
print(f"symbols: {Symbols.select().dicts().get()}")
print(f"timeframes: {Timeframes.select().dicts().get()}")
try:
    q = Candles.insert(timeframe = '1m', symbol = 'ABC').execute()
except Exception as e:
    print(f"Exception: {e}")

运行报错结果:

% test.py
symbols: {'id': 1, 'name': 'ABC'}
timeframes: {'id': 1, 'name': '1m'}
Exception: FOREIGN KEY constraint failed
%

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 10:18:00