【问题标题】:How can I create a sqlalchemy column whose default is to be equal to the primary key?如何创建一个默认等于主键的 sqlalchemy 列?
【发布时间】:2015-08-30 15:13:26
【问题描述】:

我有一个如下所示的课程:

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 在ref 之前生成带有pk 的INSERT 语句, Postgres 从左到右评估表达式(因此@987654330 生成的nextval() 调用@ 总是发生在由ref 生成的currval 调用之前)。

对于如何更好地做到这一点的任何建议,我将不胜感激!

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

【问题讨论】:

  • 这解决了什么问题?您是否正在制作“层次结构”架构?
  • 我们正在引入对象的版本控制,需要保持与旧版本客户端应用的兼容性。
  • 我不确定我是否理解两者之间的关系。 Foo.ref 是否“指向”Foo 中的另一个元组?连接是什么意思?怎么查询?
  • 我很欣赏您在这里解决更大问题的冲动,但它涉及到相当多的上下文来解释,我们已经在探索一堆不同的替代方案。我真的很想知道是否有办法让 SQLAlchemy 引用相同的序列 nextval 两次。

标签: python postgresql sqlalchemy primary-key


【解决方案1】:

可以利用 SQLAlchemy 的 ORM after_insert mapper 事件:

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)

【讨论】:

  • 酷,我试过了,它奏效了。不过有一个问题——我怎么可以在这里访问pk 属性?我习惯了它直到我提交之后才出现,但我想我的 sqlalchemy 模型在这里不完整。
  • @BenKuhn 'after_insert' 事件在 ORM 在“INSERT”之后从数据库接收到对象后立即发出。这意味着所有 db 端处理和触发器都已被调用。还有一个大警告不要使用修改Session的代码,所以你不得不回退到使用connection;)
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-30
    • 1970-01-01
    • 2018-06-12
    • 1970-01-01
    • 2016-08-03
    • 2023-02-06
    相关资源
    最近更新 更多