sqlalchemy listens_for 在 table 完全创建之前发生

sqlalchemy listens_for happening before table is fully created

我注意到 sqlalchemy 的 listens_for 装饰器在 table 完全创建之前启动,至少在我的代码中是这样。我应该怎么做才能确保它在之后开始。如果您需要更多代码,请告诉我。

错误是

Exception has occurred: ProgrammingError (psycopg2.errors.UndefinedTable) relation "organization" does not exist

我的数据库会话是在 database.py

中创建的
engine = sqlalchemy.create_engine(current_app.config['DATABASE_URL'])

db_session = scoped_session(sessionmaker(
    autocommit=False,
    autoflush=False,
    bind=engine))
Base = declarative_base(bind=engine)
Base.query = db_session.query_property()

def init_db():
    from . import models
    Base.metadata.drop_all(bind=engine)
    Base.metadata.create_all(bind=engine)

@current_app.teardown_appcontext
def shutdown_session(exception=None):
    db_session.remove()

我的模型是在 models.py

中创建的
class BaseModel(Base):
    __abstract__ = True
    created_on = Column(DateTime, default=func.now())
    updated_on = Column(DateTime, default=func.now(), onupdate=func.now())

class BaseModelId(BaseModel):
    __abstract__ = True
    id = Column(Integer, primary_key=True)

class Organization(BaseModelId):
    __tablename__ = 'organization'
    name = Column(String(128))

装饰器问题listens_for

@event.listens_for(Organization.__table__, 'after_create')
def insert_organizations(*args, **kwargs):
    db_session.add(Organization(
        name='organization',
    ))
    db_session.commit()

如果我进行一些登录,事件会在 Base.metadata.create_all(bind=engine) 完成之前被调用

如果我使用 Timer

让一两秒过去,错误消息就会消失
def insert_organizations(*args, **kwargs):
    Timer(2, _insert_organizations).start()

def _insert_organizations():
    db_session.add(Organization(
        name='organization',
    ))
    db_session.commit()

这里的问题是 Base.metadata.create_all 使用的连接与 db_session 不同,因此当 commit() 在事件侦听器中调用时 create_all 的事务尚未完成提交。

事件侦听器同时接收 table 对象和 create_all 使用的连接,因此我们可以使用这些对象来插入记录而不是会话。

@sa.event.listens_for(Organization.__table__, 'after_create')
def insert_organizations(tbl, conn, **kw):
    conn.execute(tbl.insert().values(name='organisation'))