【问题标题】:Intercept all queries on a model in SQLAlchemy在 SQLAlchemy 中拦截模型上的所有查询
【发布时间】:2016-08-06 16:05:58
【问题描述】:

我需要拦截所有与 SQLAlchemy 中的模型相关的查询,以便在任何查询方法(all()、one()、scalar() 等)所在的位置检查它执行。

我考虑过以下方法:

1。子类化查询类

我可以继承sqlalchemy.orm.Query 并覆盖执行代码,基本上从this 之类的东西开始。

但是,我正在编写一个可以在其他 SQLAlchemy 应用程序中使用的库,因此创建声明性基础(更不用说引擎和会话)超出了我的范围。

也许我错过了一些东西,并且可以在不知道会话的情况下覆盖我的模型的 Query 类?

2。使用 before_execute 核心事件

我也想过用before_execute 事件挂钩执行。

问题在于它与引擎绑定(见上文)。另外,我需要修改会话中的对象,我的印象是我无法从该事件中访问会话。


我想要做的是:

  1. session.query(MyModel).filter_by(foo="bar").all() 被执行。
  2. 拦截该查询并执行诸如将查询存储在同一数据库中的日志表中(不是字面意思,而是一组不同的东西,基本上需要与此示例操作完全相同的功能)
  3. 让查询正常执行。

我最终要做的是在查询时将另一个数据存储中的项目即时注入 SQLAlchemy 数据库。虽然这看起来很愚蠢 - 相信我,它可能没有听起来那么愚蠢(甚至更愚蠢);)。

【问题讨论】:

  • @Kosch 正如问题中所解释的那样,我认为我不会有任何运气取决于特定的引擎或会话☹。
  • @Kosch 是的,正如你所说:这个事件利用了 engine - 我不能使用它,正如我的问题中所解释的那样。我的代码是一个库,它为使用它的应用程序定义模型和此拦截代码,并且该应用程序定义创建引擎。我可以以某种方式将它传递给我的库,但是我仍然无法访问事件侦听器中的绑定会话。
  • 好吧,很明显,我可以从绑定到传递引擎的新会话创建者那里派生会话……

标签: python sqlalchemy


【解决方案1】:

before_compile 查询事件可能对您有用。

from weakref import WeakSet
from sqlalchemy import event
from sqlalchemy.orm import Query

visited_queries = WeakSet()

@event.listens_for(Query, 'before_compile')
def log_query(query):
    # You can get the session
    session = query.session

    # Prevent recursion if you want to compile the query to log it!
    if query not in visited_queries:
        visited_queries.add(query)
        # do something with query.statement

您可以查看query.column_descriptions 以查看您的模型是否正在被查询。

【讨论】:

  • 是的,就是这样!为什么我没有在文档中看到这个事件对我来说是个谜。
  • 改进:我已将weakref.WeakSet() 用于visited_queries,因此可以对仅在此处缓存但SQLAlchemy 不再引用的查询进行垃圾收集。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-26
  • 1970-01-01
  • 2017-02-15
  • 1970-01-01
  • 1970-01-01
  • 2020-02-21
  • 2021-12-27
相关资源
最近更新 更多