如何记录 django 应用程序执行的所有 SQL 查询?
我想记录所有内容,包括来自管理站点的 SQL。我看到了这个问题和常见问题解答,但我仍然不知道应该放在哪里
from django.db import connection
connection.queries
将所有内容记录到一个文件中?
所以我的问题是 - 我应该怎么做才能拥有一个记录所有 SQL 语句的文件(例如 all-sql.log)?
将以下代码片段与
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 答案
在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': { '级别':'调试', '处理程序':['控制台'], }, } }
要在测试期间记录 SQL 查询,您需要两件事:
django.db.backends
记录器已启用并且@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()
也许可以看看 https://github.com/django-debug-toolbar/django-debug-toolbar
它可以让您查看给定页面生成的所有查询。 以及它们发生位置的堆栈跟踪等。
编辑:要将所有 SQL 查询记录到文件等,那么您将需要创建一些中间件。 中间件根据每个请求运行。 有几个 Django 片段可以用于此类事情:
那些与打印到终端有关,但调整它们以使用 python 的日志库并不困难。
Django 1.3 将所有 SQL 语句记录到 django.db.backends 记录器:
https://docs.djangoproject.com/en/dev/ref/logging/#django-db-backends
在现代 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)
您只需要:
@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 的回答!
如果您想通过设置来切换此功能,请在 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 的日志配置使此工作得以实现。
我不知道如何将 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)
那么,如果你换一个人,如下图所示:
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
您需要将其放入中间件包中。中间件位于 webserver/django 核心和所有视图之间。它可以在请求之前进行预处理,并在请求完成之后进行后处理。例如,将查询保存到文件中。