How can I create a sqlalchemy column whose default is to be equal to the primary key?

最后都变了- 提交于 2019-12-08 03:17:27

问题


I have a class that looks like this:

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

I want to make another field, ref, that defaults to being equal to pk for newly-created objects. Unfortunately, I'm using Postgres, which has a non-standard nextval() function, so I can't simply make both of the columns default to the Sequence object.

Here's my current solution:

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

However this depends on two things: SQLAlchemy generating an INSERT statement with pk before ref, and Postgres evaluating expressions from left to right (so the nextval() call generated by pk always happens before the currval call generated by ref).

I would greatly appreciate any suggestions for how to do this better!

EDIT: There's also the more solution of setting default=-1 or something and forcing the caller to update the ref field. That's safer and more robust to changes in SQLA/Postgres semantics but pretty inconvenient for clients of the class.


回答1:


It is possible to utilize SQLAlchemy's ORM after_insert mapper event:

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)



回答2:


I recommend using a trigger to set that value. Though I haven't tested this myself, you could have a trigger activate AFTER INSERT that reads the new row's PK value and update the ref column with that value. It seems somewhat similar to Postgresql insert trigger to set value except that you want the trigger to be after the insert, instead of before.



来源:https://stackoverflow.com/questions/32277403/how-can-i-create-a-sqlalchemy-column-whose-default-is-to-be-equal-to-the-primary

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!