如何在 Django 中记录所有 SQL 查询?
- 2025-02-10 08:57:00
- admin 原创
- 52
问题描述:
如何记录我的 django 应用程序执行的所有 SQL 查询?
我想记录所有内容,包括来自管理站点的 SQL。我看到了这个问题和常见问题解答,但我仍然不知道应该把这些放在哪里
from django.db import connection
connection.queries
将所有内容记录到一个文件中?
所以我的问题是 - 我应该怎么做才能得到一个记录所有 SQL 语句的文件(比如说 all-sql.log)?
解决方案 1:
将以下代码片段与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 的回答修改
解决方案 2:
在settings.py中添加以下加粗语句
如果调试:
导入日志
l = logs.getLogger('django.db.backends') 复制代码
l.设置级别(日志记录.DEBUG)
添加Handler(logging.StreamHandler())
记录 = {
‘版本’:1,
‘disable_existing_loggers’:false,
‘过滤器’:{
‘需要_debug_false’:{
'()':'django.utils.log.RequireDebugFalse'
}
},
‘处理程序’:{
‘邮件管理员’:{
‘级别’:‘错误’,
‘过滤器’:[‘require_debug_false’],
‘类’:‘django.utils.log.AdminEmailHandler’
},'安慰': {
‘级别’:‘调试’,
‘类’:‘logging.StreamHandler’,
},
},
‘记录员’:{
‘django.request’:{
‘处理程序’:[‘mail_admins’],
‘级别’:‘错误’,
‘传播’:真实,
}, 'django.db.backends.sqlite3': {
‘级别’:‘调试’,
‘处理程序’:[‘控制台’],
},
}
}
资源/信用
解决方案 3:
要在测试期间记录 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()
解决方案 4:
也许看看https://github.com/django-debug-toolbar/django-debug-toolbar
它会让您看到给定页面生成的所有查询。以及它们发生位置的堆栈跟踪等。
编辑:要将所有 SQL 查询记录到文件等,那么您需要创建一些中间件。中间件在每个请求时运行。有几种 Django 代码片段可用于此类操作:
这些与打印到终端有关,但调整它们以使用 python 的日志库并不难。
解决方案 5:
Django 1.3 将所有 SQL 语句记录到django.db.backends记录器:
https://docs.djangoproject.com/en/dev/ref/logging/#django-db-backends
解决方案 6:
在现代 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)
解决方案 7:
您只需要:
@override_settings(DEBUG=True)
如果您已经有 SQL 调试语句被打印在runserver
。
将装饰器添加到您的class TestA(TestCase)
或test_function
:
@override_settings(DEBUG=True)
class TestA(TestCase):
...
@override_settings(DEBUG=True)
def test_function(self):
...
感谢@Janusz Skonieczny 的回答!
解决方案 8:
如果您想要通过设置来切换此功能,请在 settings.py 中执行以下操作:
if LOG_DB_QUERIES:
LOGGING["handlers"]["console"] = {
"level": "DEBUG", "class": "logging.StreamHandler"
}
LOGGING["loggers"]["django.db.backends"] = {
"level": "DEBUG", "handlers": ["console"]
}
另请注意,只有DEBUG = True
在 settings.py 中,此功能才会起作用。
感谢@Gian Marco提供的日志配置使得此功能能够正常工作。
解决方案 9:
我不知道如何将Django 中的所有 SQL 查询记录到文件中。
但是,我知道如何使用下面的代码来获取Django Admin中的SQL 查询部分。 *您还可以看到我的答案,解释如何在Django View中获取SQL 查询的部分:
from django.db import connection
connection.queries
例如,您可以在adminconnection.queries
中使用覆盖来获取SQL 查询,save_model()
如下所示:Person
# "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
解决方案 10:
您需要将其放入中间件包中。中间件位于 webserver/django 核心和所有视图之间。它可以在请求之前进行预处理,并在请求完成后进行后处理。例如,将查询保存到文件中。