如何在插入对象后发出SQLAlchemy自定义DDL?

时间:2015-11-29 22:08:02

标签: postgresql python-3.x sqlalchemy flask-sqlalchemy materialized-views

我有一个PostgreSQL物化视图,可以计算一些有关制造商的数据。

我创建了一个SQLAlchemy自定义DDL命令来刷新视图:

from sqlalchemy.schema import DDLElement
from sqlalchemy.ext import compiler

class RefreshMaterializedView(DDLElement):
    '''Target expected to be a view name string'''
    def __init__(self, concurrently):
        self.concurrently = concurrently

@compiler.compiles(RefreshMaterializedView)
def compile(element, compiler, **kw):
    if element.concurrently:
        return "REFRESH MATERIALIZED VIEW CONCURRENTLY %s" % (element.target)
    return "REFRESH MATERIALIZED VIEW %s" % (element.target)

class ManufacturerMaterializedView(db.Model):
    @classmethod 
    def refresh(cls, concurrently=True, bind=db.session):
        RefreshMaterializedView(concurrently).execute(
                                target=cls.__table__.fullname, bind=bind)

以下是我目前在代码中使用它的方式:

db.session.add(new_manufacturer_instance)
ManufacturerMaterializedViewClass.refresh() # bound to the same session
db.session.flush()
# some other stuff
db.session.add(another_manufacturer_instance) # still in the same PostgreSQL transaction
ManufacturerMaterializedViewClass.refresh()
db.session.commit()

期望的行为:

  1. 在<_ strong>创建new_manufacturer_instance之后,物化视图会刷新
  2. 我可以重复插入新制造商并在同一会话中多次调用ManufacturerMaterializedViewClass.refresh(),但刷新只会在所有INSERT / {{1后的会话结束时发出一次已发出所有对象的/ UPDATE语句。其他对象类型会影响此物化视图的输出,因此需要在修改这些对象后发出此刷新语句。
  3. 以下是使用DELETE查看Flask-Sqlalchemy查询日志时当前发生的情况:

    SQLALCHEMY_ECHO = True

    正如您所看到的,调用$ python manage.py shell >>> ManufacturerFactory() # creates a new manufacturer instance and adds it to the session <Manufacturer #None:'est0'> >>> ManufacturerMV.refresh() 2015-11-29 13:33:44,811 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 2015-11-29 13:33:44,812 INFO sqlalchemy.engine.base.Engine REFRESH MATERIALIZED VIEW CONCURRENTLY manufacturer_mv 2015-11-29 13:33:44,812 INFO sqlalchemy.engine.base.Engine {} >>> db.session.flush() 2015-11-29 13:34:13,745 INFO sqlalchemy.engine.base.Engine INSERT INTO manufacturer (name, website, logo, time_updated) VALUES (%(name)s, %(website)s, %(logo)s, %(time_updated)s) RETURNING manufacturer.id 2015-11-29 13:34:13,745 INFO sqlalchemy.engine.base.Engine {'logo': '/static/images/16-rc_gear_essential.jpg', 'website': 'http://hermann.com/', 'time_updated': None, 'name': 'est0'} >>>> db.session.commit() 2015-11-29 13:42:58,160 INFO sqlalchemy.engine.base.Engine COMMIT 会立即向数据库发出SQL,甚至在refresh()之前,会抢占任何其他插入/更新语句。但是,在session.flush()关闭事务之前,DDL实际上并不是由PostgreSQL执行的。

    我应该如何修改我的DDL / classmethod以达到我想要的行为?

    我查看了ORM events,但不太确定如何在我的用例中利用它们。我不希望在我的应用程序发出的每session.commit()个时调用一次刷新。刷新此特定视图是一项相当昂贵的操作,因此只有当我在当前事务/ session.commit()内实际调用refresh()时才会发生。

0 个答案:

没有答案