【问题标题】:How to correctly add Foreign Key constraints to SQLite DB using SQLAlchemy [duplicate]如何使用 SQLAlchemy 正确地将外键约束添加到 SQLite DB [重复]
【发布时间】:2015-10-25 23:13:22
【问题描述】:

我对 SQLAlchemy 很陌生,我正在努力弄明白。

请记住以下测试设置:

class Nine(Base):
    __tablename__ = 'nine'
    __table_args__ = (sqlalchemy.sql.schema.UniqueConstraint('nine_b', name='uq_nine_b'), )

    nine_a = sqlalchemy.Column(sqlalchemy.dialects.sqlite.INTEGER(), primary_key=True, autoincrement=False, nullable=False)
    nine_b = sqlalchemy.Column(sqlalchemy.String(20), nullable=False)


class Seven(Base):
    __tablename__ = 'seven'
    __table_args__ = (sqlalchemy.sql.schema.PrimaryKeyConstraint('seven_a', 'seven_b'),
                      sqlalchemy.sql.schema.Index('fk_seven_c_nine_a_idx', 'seven_c'),)

    seven_a = sqlalchemy.Column(sqlalchemy.dialects.sqlite.INTEGER(), nullable=False)
    seven_b = sqlalchemy.Column(sqlalchemy.dialects.sqlite.INTEGER(), nullable=False)
    seven_c = sqlalchemy.Column(sqlalchemy.dialects.sqlite.INTEGER(), sqlalchemy.ForeignKey('nine.nine_a'), nullable=False)
    seven_d = sqlalchemy.Column(sqlalchemy.dialects.sqlite.INTEGER(), nullable=False)

    nine = sqlalchemy.orm.relationship(Nine, backref=sqlalchemy.orm.backref('seven'), uselist=False)


class Three(Base):
    __tablename__ = 'three'
    __table_args__ = (sqlalchemy.sql.schema.UniqueConstraint('three_b', 'three_c', name='uq_three_b_c'),
                      sqlalchemy.sql.schema.Index('fk_three_c_seven_a_idx', 'three_c'), )

    three_a = sqlalchemy.Column(sqlalchemy.dialects.sqlite.INTEGER(), primary_key=True, autoincrement=True, nullable=False)
    three_b = sqlalchemy.Column(sqlalchemy.dialects.sqlite.INTEGER(), nullable=False)
    three_c = sqlalchemy.Column(sqlalchemy.dialects.sqlite.INTEGER(), sqlalchemy.ForeignKey('seven.seven_a'), nullable=False)

    seven = sqlalchemy.orm.relationship(Seven, backref=sqlalchemy.orm.backref('three'), uselist=False)

转换为以下 DDL:

CREATE TABLE nine (
    nine_a INTEGER NOT NULL, 
    nine_b VARCHAR(20) NOT NULL, 
    PRIMARY KEY (nine_a), 
    CONSTRAINT uq_nine_b UNIQUE (nine_b)
);

CREATE TABLE seven (
    seven_a INTEGER NOT NULL, 
    seven_b INTEGER NOT NULL, 
    seven_c INTEGER NOT NULL, 
    seven_d INTEGER NOT NULL, 
    PRIMARY KEY (seven_a, seven_b), 
    FOREIGN KEY(seven_c) REFERENCES nine (nine_a)
);

CREATE INDEX fk_seven_c_nine_a_idx ON seven (seven_c);

CREATE TABLE three (
    three_a INTEGER NOT NULL, 
    three_b INTEGER NOT NULL, 
    three_c INTEGER NOT NULL, 
    PRIMARY KEY (three_a), 
    CONSTRAINT uq_three_b_c UNIQUE (three_b, three_c), 
    FOREIGN KEY(three_c) REFERENCES seven (seven_a)
);

CREATE INDEX fk_three_c_seven_a_idx ON three (three_c);

所有表格都是空的。然后,如下代码语句:

session.add(Nine(nine_a=1, nine_b='something'))
session.add(Nine(nine_a=2, nine_b='something else'))
session.commit()

session.add(Seven(seven_a=7, seven_b=7, seven_c=7, seven_d=7))
session.commit()

session.add(Three(three_a=3, three_b=3, three_c=3))
sessionDB.commit()

谁能解释一下为什么上面的代码 sn-p 执行没有错误? FK 约束是否应该停止在seventhree 中插入新行?我认为 FK 在类本身中的描述方式有问题,但我不知道问题出在哪里(以及如何解决)。

[编辑 1]

为所有类添加__table_args__(忘记包含它们)。

[编辑 2]

添加 DDL 以供进一步参考。

【问题讨论】:

    标签: python sqlite sqlalchemy foreign-keys foreign-key-relationship


    【解决方案1】:

    默认情况下,SQLite 不强制执行 ForeignKey 约束(请参阅此处http://www.sqlite.org/pragma.html#pragma_foreign_keys

    要启用,请在此处关注以下文档:http://docs.sqlalchemy.org/en/latest/dialects/sqlite.html#foreign-key-support

    这是官方文档的复制粘贴:

    SQLite 在为表发出 CREATE 语句时支持 FOREIGN KEY 语法,但默认情况下,这些约束对表的操作没有影响。

    对 SQLite 的约束检查具有三个先决条件:

    • 必须至少使用 3.6.19 版的 SQLite
    • 必须在未启用 SQLITE_OMIT_FOREIGN_KEY 或 SQLITE_OMIT_TRIGGER 符号的情况下编译 SQLite 库。
    • PRAGMA foreign_keys = ON 语句必须在使用前在所有连接上发出。 SQLAlchemy 允许通过使用事件为新连接自动发出 PRAGMA 语句:
    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()
    

    【讨论】:

    • 我在运行插入之前发出PRAGMA foreign_keys = ON(命令PRAGMA foreign_keys 返回1。不幸的是结果相同。
    • 我已经在数据库级别测试了 FK 约束为 ON。但似乎每个连接都需要打开它(http://stackoverflow.com/a/9835781/1237714)。事情开始变得正常。 (请在答案中包含代码 sn-p(例如,使用事件)。)
    猜你喜欢
    • 2019-07-30
    • 2018-03-05
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 2014-01-17
    • 2012-01-13
    • 2021-04-07
    相关资源
    最近更新 更多