每个执行的SQL语句的信号/方法

gue*_*tli 12 django

根据这个已有12年历史的问题,django不支持每个执行的sql语句的信号:https : //code.djangoproject.com/ticket/5415

我在debug = False的生产环境中需要它。

这意味着将覆盖连接。查询不起作用。

有没有办法在每个sql语句后运行一些自定义代码(即使debug = False)?

Lou*_*uis 9

我看了看Django是如何填充的connection.queries。何时DEBUG = True,所有后端使用的基础数据库后端代码用来包装数据库特定的游标CursorDebugWrapper。否则,使用CursorWrapper。从理论上讲,即使DEBUG = False通过覆盖queries_logged属性或force_debug_cursor在数据库连接对象上设置标志,也可以强制Django填充它。这两种方法都会迫使Django CursorDebugWrapper即使在DEBUGis 时也要使用False。但是,我不推荐这种方法,因为这种方法CursorDebugWrapper在您唯一需要知道的是执行查询的情况下效率不高。例如,除了填充外,还将connection.queries查询记录到记录器中。如果您不需要此日志记录,那么这只是浪费。

因此,从CursorDebugWrapper工作原理中获得启发,我想出了一种自定义方式来了解何时进行SQL查询。

我创建了一个应用程序,first其名称__init__.py为:

from django.db.backends import utils
from contextlib import contextmanager

# This is inspired by Django's stock CursorDebugWrapper class.
class Mixin(object):

    def execute(self, sql, params=None):
        with self.notify(sql, params, use_last_executed_query=True):
            return super().execute(sql, params)

    def executemany(self, sql, param_list):
        with self.notify(sql, param_list):
            return super().executemany(sql, param_list)

    @contextmanager
    def notify(self, sql=None, params=None, use_last_executed_query=False):
        try:
            yield
        finally:
            if use_last_executed_query:
                sql = self.db.ops.last_executed_query(self.cursor, sql, params)
            # I've used print for this proof-of-concept, replace with whatever
            # mechanism suits you.
            print("Executed: ", sql)

class CustomWrapper(Mixin, utils.CursorWrapper):
    pass

class CustomDebugWrapper(Mixin, utils.CursorDebugWrapper):
    pass

utils.CursorWrapper = CustomWrapper
utils.CursorDebugWrapper = CustomDebugWrapper
Run Code Online (Sandbox Code Playgroud)

然后在我的settings.py文件中,将first应用程序放在第一位INSTALLED_APPS。这样就可以使其__init__.py文件在访问数据库的任何内容之前执行。

这实际上是在用自定义的库CursorWrapperCursorDebugWrapper类替换库存和类,以使他们知道何时发生SQL查询。此更改对Django随附的所有后端均生效。

我不知道像我在上面那样一口气添加此功能的另一种方法。我首先查看是否可以从现有后端中派生出新后端。我确定它是可行的,但需要大量样板。同样,同时使用多个后端的项目必须为每个最初使用的股票后端派生一个新的后端。