【问题标题】:invalid values accepted for insert despite ForeignKey [duplicate]尽管 ForeignKey [重复],但接受插入的无效值
【发布时间】:2018-04-09 02:01:04
【问题描述】:

在下面的代码中,为什么插入表 t1 时没有错误? t1 中的 b 列是外键,因此它应该只接受 t2 中 c 列的值,但不知何故我可以插入“bar”而不会出错。我在这里错过了什么?

from sqlalchemy import create_engine, MetaData, Table, Column, Unicode, ForeignKey

engine = create_engine(r'sqlite:///XXXXXXX.db', echo=True)
metadata = MetaData()
t1 = Table('t1', metadata,
           Column('a', Unicode(), primary_key=True),
           Column('b', Unicode(), ForeignKey('t2.c')))
t2 = Table('t2', metadata,
           Column('c', Unicode(), primary_key=True))
metadata.create_all(engine)
conn = engine.connect()
conn.execute(t2.insert().values(c='first'))
conn.execute(t2.insert().values(c='second'))
conn.execute(t1.insert().values(a='foo', b='bar'))

编辑

我认为这个问题不应该被标记为链接问题的副本。链接的问题是关于如何强制执行外键假设您已经知道默认情况下它没有打开。在我的问题中,我观察到一个奇怪的行为(违反外键约束)并询问根本原因。

【问题讨论】:

  • 检查您是否有enabled foreign key support,以防万一。
  • 阅读SQLA docs on the subject。有一些先决条件,您必须在使用前在每个新连接上发出 PRAGMA foreign_keys=ON
  • 谢谢,我从 SQLA 文档中复制了部分代码,令我惊讶的是,它就像一个魅力。我很惊讶,因为我是 python 的初学者,而且我以前从未使用过事件。我不太明白的部分是 set_sqlite_pragma 函数是如何工作的。它的论点是什么?它们来自哪里?
  • 您是否熟悉 Python 装饰器的一般工作方式?装饰的函数被传递给装饰器,就像在函数定义之后调用set_sqlite_pragma = event.listens_for(set_sqlite_pragma)一样。 event.listens_for 装饰器将装饰函数注册为事件侦听器,然后在 SQLA 触发事件时调用它。

标签: python sqlalchemy


【解决方案1】:

感谢 Ilja 朝着正确的方向前进。我按以下方式修改了代码,现在它按预期工作,即在最后一行引发 IntegrityError。

from sqlalchemy import create_engine, MetaData, Table, Column, Unicode, ForeignKey
from sqlalchemy.engine import Engine
from sqlalchemy import event


@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()

engine = create_engine(r'sqlite:///XXXXXXX.db', echo=True)
metadata = MetaData()
t1 = Table('t1', metadata,
           Column('a', Unicode(), primary_key=True),
           Column('b', Unicode(), ForeignKey('t2.c')))
t2 = Table('t2', metadata,
           Column('c', Unicode(), primary_key=True))
metadata.create_all(engine)
conn = engine.connect()
conn.execute(t2.insert().values(c='first'))
conn.execute(t2.insert().values(c='second'))
conn.execute(t1.insert().values(a='foo', b='bar'))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-03
    • 2017-07-02
    • 2021-04-13
    • 2019-06-12
    • 1970-01-01
    • 2021-02-08
    • 2022-01-11
    相关资源
    最近更新 更多