Peewee:不理解代码生成原因的概念 "FOREIGN KEY constraint failed"

Peewee: Not understanding concept of why code is generating "FOREIGN KEY constraint failed"

编辑

我使用 DB Browser(图形客户端)仔细查看了架构,发现架构将 timeframe_idsymbol_id 显示为 INTEGER 而不是 VARCHAR这是 .schemasqlite3 客户端输出中产生的内容:

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>

在注意到这一点和外键上的 absorbing a bit more content 之后,我发现我对外键这个概念的理解存在一些缺陷,并且对 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 table。我不断收到 FOREIGN KEY constraint failed 错误,但不确定原因。

我是数据库编程的新手,但从概念上讲,我理解 this should work 因为 Symbols.nameTimeframes.name 已经包含了 Candles.symbol 和 [=29] 的字段=] 分别用作外键。

The FOREIGN KEY constraint prevents invalid data from being inserted into the foreign key column, because it has to be one of the values contained in the parent table.

我已经在示例代码中添加了日志记录,以尝试展示我一直在做的工作,以确保我希望看到的所有值都存在。

我显然误会了什么。任何见解将不胜感激。

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
%

默认情况下,peewee 外键将指向相关模型的主键(默认情况下是一个自动增量整数)。因此,您的原始示例尝试使用 'ABC' 作为符号,但它应该是名称为“ABC”的符号的“id”。在您更新的示例中,您明确指定“名称”列作为 FK 目标,此时一切正常:

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

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

Symbols.insert(name='ABC').execute()
Timeframes.insert(name='1m').execute()
# Works fine:
q = Candles.insert({'timeframe': '1m', 'symbol': 'ABC'}).execute()

另一种实现类似的方法,是使用符号name/timeframe名称作为主键:

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

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

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

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

Symbols.insert(name='ABC').execute()
Timeframes.insert(name='1m').execute()
print(f"symbols: {Symbols.select().dicts().get()}")
print(f"timeframes: {Timeframes.select().dicts().get()}")
q = Candles.insert({'timeframe': '1m', 'symbol': 'ABC'}).execute()

请注意,使用名称作为 PK 时不存在“id”列:

symbols: {'name': 'ABC'}
timeframes: {'name': '1m'}