如何在 Django 中记录所有 SQL 查询?

问题描述 投票:0回答:10

如何记录 django 应用程序执行的所有 SQL 查询?

我想记录所有内容,包括来自管理站点的 SQL。我看到了这个问题常见问题解答,但我仍然不知道应该放在哪里

from django.db import connection
connection.queries

将所有内容记录到一个文件中?

所以我的问题是 - 我应该怎么做才能拥有一个记录所有 SQL 语句的文件(例如 all-sql.log)?

python sql django logging django-database
10个回答
262
投票

将以下代码片段与

LOGGING
中的
settings.py
字段合并:

LOGGING = {
    'version': 1,
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        }
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
        }
    },
    'loggers': {
        'django.db.backends': {
            'level': 'DEBUG',
            'handlers': ['console'],
        }
    }
}

调整自@acardenas89 答案


60
投票

在settings.py中添加以下粗体语句


如果调试:
    导入日志记录
    l =logging.getLogger('django.db.backends')
    l.setLevel(日志记录.DEBUG)
    l.addHandler(logging.StreamHandler())


记录 = {
    “版本”:1,
    “disable_existing_loggers”:错误,
    “过滤器”:{
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    '处理程序':{
        '邮件管理员':{
            '级别':'错误',
            '过滤器':['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        },'控制台': {
            '级别':'调试',
            'class': 'logging.StreamHandler',
        },
    },
    '记录器':{
        'django.request': {
            '处理程序':['mail_admins'],
            '级别':'错误',
            “传播”:确实,
        },'django.db.backends.sqlite3': {
            '级别':'调试',
            '处理程序':['控制台'],
        },
    }
}
  

资源/信用


32
投票

要在测试期间记录 SQL 查询,您需要两件事:

  1. django.db.backends
    记录器已启用并且
  2. @override_settings(DEBUG=True)
    装饰器.

测试运行程序将默认设置 DEBUG=False,忽略您在 DJANGO_SETTINGS_MODULE 中设置的内容。

最低设置:

# https://docs.djangoproject.com/en/dev/ref/settings/#logging
LOGGING = {
    'version': 1,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'level': 'DEBUG',
        },
    },
    'root': {
        'handlers': ['console'],
    }
}

示例测试用例:

from django.contrib.auth.models import User
from django.test import TestCase, override_settings


class UserTests(TestCase):

    # To log queries in tests you need to manually override DEBUG setting
    # because testing sets DEBUG=False by default

    @override_settings(DEBUG=True)
    def test_create_user(self):
        User.objects.create()

24
投票

也许可以看看 https://github.com/django-debug-toolbar/django-debug-toolbar

它可以让您查看给定页面生成的所有查询。 以及它们发生位置的堆栈跟踪等。

编辑:要将所有 SQL 查询记录到文件等,那么您将需要创建一些中间件。 中间件根据每个请求运行。 有几个 Django 片段可以用于此类事情:

那些与打印到终端有关,但调整它们以使用 python 的日志库并不困难。


16
投票

Django 1.3 将所有 SQL 语句记录到 django.db.backends 记录器:

https://docs.djangoproject.com/en/dev/ref/logging/#django-db-backends


4
投票

在现代 Django 中,我们获得了挂钩和检测 sql 查询的原生方法,无需安装额外的依赖项。 OP 要求提供所有查询,但这也可能具有很高的情境用途。

import time

class QueryLogger:
    def __init__(self):
        self.queries = []

    def __call__(self, execute, sql, params, many, context):
        current_query = {"sql": sql, "params": params, "many": many}
        start = time.monotonic()
        try:
            result = execute(sql, params, many, context)
        except Exception as e:
            current_query["status"] = "error"
            current_query["exception"] = e
            raise
        else:
            current_query["status"] = "ok"
            return result
        finally:
            duration = time.monotonic() - start
            current_query["duration"] = duration
            self.queries.append(current_query)
(...)

# say, in Django Shell we would like to see 
# whether .exists() is faster than .count() 
# and what raw SQL it actually runs

import pprint
from django.db import connection
    
ql = QueryLogger()
with connection.execute_wrapper(ql):
    Book.objects.filter(author="Uncle Bob").exists()
    Book.objects.filter(author="Uncle Bob").count()

pprint.pprint(ql.queries)

3
投票

您只需要:

@override_settings(DEBUG=True)

如果您已经在

runserver
中打印了 SQL 调试语句。

将装饰器添加到您的

class TestA(TestCase)
test_function
:

@override_settings(DEBUG=True)
class TestA(TestCase):
...

    @override_settings(DEBUG=True)
    def test_function(self):
    ...

感谢@Janusz Skonieczny 的回答!


1
投票

如果您想通过设置来切换此功能,请在 settings.py 中执行类似以下操作:

if LOG_DB_QUERIES:
    LOGGING["handlers"]["console"] = {
        "level": "DEBUG", "class": "logging.StreamHandler"
    }
    LOGGING["loggers"]["django.db.backends"] =  {
        "level": "DEBUG", "handlers": ["console"]
    }
    

另外,请注意,只有在 settings.py 中有

DEBUG = True
时,这才有效。

感谢 @Gian Marco 的日志配置使此工作得以实现。


1
投票

我不知道如何将 Django 中的所有 SQL 查询记录到文件中。

但是,我知道如何使用下面的代码来获取Django Admin中的SQL查询部分。 *您还可以看到我的回答解释如何在Django视图中获取SQL查询的部分

from django.db import connection
connection.queries

例如,您可以在

connection.queries
admin 中的 overridden
save_model()
中使用
Person
来获取 SQL 查询,如下所示:

# "store/admin.py"

from .models import Person
from django.db import connection

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    # Here
    def save_model(self, request, obj, form, change):
        obj.save()
        for query in connection.queries: # Here
            print(query)

那么,如果你换一个人,如下图所示:

enter image description here

SQL 查询打印在控制台上,如下所示:

{'sql': 'SELECT "django_session"."session_key", "django_session"."session_data", "django_session"."expire_date" FROM "django_session" WHERE ("django_session"."expire_date" > \'2022-12-24T06:47:45.799803+00:00\'::timestamptz AND "django_session"."session_key" = \'7spdc2c5h3g2v5hjc898eqphf11g9eck\') LIMIT 21', 'time': '0.000'}
{'sql': 'SELECT "account_customuser"."id", "account_customuser"."password", "account_customuser"."last_login", "account_customuser"."is_superuser", "account_customuser"."first_name", "account_customuser"."last_name", "account_customuser"."is_staff", "account_customuser"."is_active", "account_customuser"."date_joined", "account_customuser"."email", "account_customuser"."phone", "account_customuser"."my_order" FROM "account_customuser" WHERE "account_customuser"."id" = 1 LIMIT 21', 'time': '0.000'}
{'sql': 'SELECT "store_person"."id", "store_person"."name" FROM "store_person" WHERE "store_person"."id" = 191 LIMIT 21', 'time': '0.000'}
{'sql': 'UPDATE "store_person" SET "name" = \'David\' WHERE "store_person"."id" = 191', 'time': '0.000'}
[24/Dec/2022 15:47:45] "POST /admin/store/person/191/change/ HTTP/1.1" 302 0
[24/Dec/2022 15:47:46] "GET /admin/store/person/ HTTP/1.1" 200 22584
[24/Dec/2022 15:47:46] "GET /admin/jsi18n/ HTTP/1.1" 200 3195

0
投票

您需要将其放入中间件包中。中间件位于 webserver/django 核心和所有视图之间。它可以在请求之前进行预处理,并在请求完成之后进行后处理。例如,将查询保存到文件中。

© www.soinside.com 2019 - 2024. All rights reserved.