如何在SQLALchemy Core中设置CONSTRAINTS ... DEFERRED

时间:2015-09-11 23:38:10

标签: python postgresql transactions sqlalchemy

我正在使用SQLAlchemy和PostgreSQL。 Postgres支持执行延迟约束,这允许我们推迟检查表上的约束,直到事务结束。

例如,在SQLAlchemy中,我可能会定义一个这样的表:

t_group_categories = Table('group_categories', metadata,
    Column('id', Integer, primary_key=True),
    Column('group_id', Integer, ForeignKey('groups.id', deferrable=True))
)

SQLAlchemy会生成一个CREATE TABLE语句,如下所示:

CREATE TABLE group_categories
(
  id serial NOT NULL,
  group_id integer,
  CONSTRAINT group_categories_pkey PRIMARY KEY (id),
  CONSTRAINT group_categories_group_id_fkey FOREIGN KEY (group_id)
      REFERENCES groups (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE DEFERRABLE INITIALLY IMMEDIATE
)

据我了解,DEFERRABLE INITIALLY IMMEDIATE表示FOREIGN KEY约束 将被视为不可延迟的约束,除非明确告知 否则,这正是我想要的。

问题是我似乎无法找到有关如何让SQLAlchemy核心在事务内部实际发出SET CONSTRAINTS ... DEFERRED命令的任何信息。 例如,假设我有以下代码:

connection = engine.connect()
...
with connection.begin() as transaction:
    # Create a group
    r = connection.execute(
        t_groups.insert().values(...)
    )
    group_id = r.inserted_primary_key

    # Assign a category to the group (ERROR!)
    r2 = connection.execute(
        t_group_categories.insert().values(group_id=group_id, ...)
    )

第一个块只是创建一个新组。然后第二个块尝试分配该组 我们刚创建了一个类别。问题是如果没有特殊的SET CONSTRAINTS ... DEFERRED, 我们实际上无法在不违反外键约束的情况下创建group_categories条目 在桌子上,因为交易尚未提交。

在这个实例中我想做的是推迟检查约束,直到事务提交为止。 如何在事务完成之前实际推迟约束检查?

注意:

  • 问题所在 How to SET CONSTRAINTS DEFERRED in sqlalchemy expression language?类似,但OP对使用DEFERRABLE INITIALLY DEFERRED感兴趣,我不愿意这样做。相反(如果可能的话),我希望将约束保持为DEFERRABLE INITIALLY IMMEDIATE并明确标记需要延迟约束的实例。
  • SQLAlchemy是生成DEFERRABLE INITIALLY DEFERRED约束的那个,所以我希望/假设它有一种表达方式在另一边实际使用这个约束(即表达语言方式发出{{1 }}。

更新

  • SET CONSTRAINTS ... DEFERRED似乎也没有任何效果;我仍然遇到IntegrityError。
  • 在事务块内执行connection.execute("SET CONSTRAINTS ALL DEFERRED")也会返回IntegrityError。

1 个答案:

答案 0 :(得分:1)

this question中所述,外键约束can't be deferred,即使它们被声明为:

  

即使约束被宣布为可延迟,也不能推迟除NO ACTION检查以外的参考动作。