如何创建sqlalchemy列,其默认值等于主键?

时间:2015-08-28 18:16:11

标签: python postgresql sqlalchemy primary-key

我有一个看起来像这样的课程:

class Foo(Base):
    pk = Column(Integer, Sequence('foo'), primary_key=True)

我想创建另一个字段ref,对于新创建的对象,默认等于pk。不幸的是,我使用的Postgres有一个non-standard nextval() function,所以我不能简单地将两个列都默认为Sequence对象。

这是我目前的解决方案:

class Foo(Base):
    pk = Column(Integer, Sequence('foo'), primary_key=True)
    ref = Column(Integer, index=True, nullable=False, default=func.currval('foo'))

然而,这取决于两件事:SQLAlchemy在pk之前生成带ref的INSERT语句, Postgres从左到右评估表达式(所以{{1} } nextval()生成的调用始终发生在pk生成的currval调用之前。

我非常感谢有关如何做得更好的任何建议!

编辑:还有更多设置ref或其他内容并强制调用者更新default=-1字段的解决方案。这对SQLA / Postgres语义的变化更安全,更健壮,但对于该类客户来说非常不方便。

2 个答案:

答案 0 :(得分:2)

可以使用SQLAlchemy的ORM after_insert映射器事件:

from sqlalchemy import event

# Model from OP
class Foo(Base):
    pk = Column(Integer, Sequence('foo'), primary_key=True)
    ref = Column(Integer, index=True, nullable=False, default=-1)

    @staticmethod
    def fill_ref(mapper, connection, target):
        # Note: You cannot use ORM in the event callbacks
        connection.execute(mapper.mapped_table.update()
                                 .values(ref=target.pk))
                                 .where(table.c.pk==target.pk))

event.listen(Foo, 'after_insert', Foo.fill_ref)

答案 1 :(得分:1)

我建议使用触发器来设置该值。虽然我自己没有对此进行测试,但您可以使用触发器激活AFTER INSERT来读取新行的PK值并使用该值更新ref列。它似乎有点类似于Postgresql insert trigger to set value,除了你想要触发器在插入之后,而不是之前。