Answers:
请参阅文档FAQ:“ 如何查看Django正在运行的原始SQL查询? ”
django.db.connection.queries
包含SQL查询的列表:
from django.db import connection
print(connection.queries)
查询集还具有包含要执行的查询的query
属性:
print(MyModel.objects.filter(name="my name").query)
请注意,查询的输出不是有效的SQL,因为:
“ Django从未实际插入参数:它将查询和参数分别发送到数据库适配器,后者执行适当的操作。”
来自Django错误报告#17741。
因此,您不应将查询输出直接发送到数据库。
str()
函数,该函数调用内部__str__()
方法。例如,str(MyModel.objects.filter(name="my name").query)
我还建议您使用IPython和项目的Django Shell。制表符补全然后提供对象自省。由于Django因其可靠的命名方案而闻名,因此这种方法趋于非常有用。
query
是无效的SQL,因为“ Django从未实际插入参数:它会将查询和参数分别发送给数据库适配器,后者执行适当的操作。” 资料来源:code.djangoproject.com/ticket/17741
Django扩展具有带参数的命令shell_plusprint-sql
./manage.py shell_plus --print-sql
在django-shell中,所有执行的查询将被打印
例如:
User.objects.get(pk=1)
SELECT "auth_user"."id",
"auth_user"."password",
"auth_user"."last_login",
"auth_user"."is_superuser",
"auth_user"."username",
"auth_user"."first_name",
"auth_user"."last_name",
"auth_user"."email",
"auth_user"."is_staff",
"auth_user"."is_active",
"auth_user"."date_joined"
FROM "auth_user"
WHERE "auth_user"."id" = 1
Execution time: 0.002466s [Database: default]
<User: username>
q = Query.objects.values('val1','val2','val_etc')
print q.query
m = MyModel.objects.get(...)
接着执行m.query
m
不再是一个查询集。使用q = MyModel.objects.filter(...)
,然后q.query
,然后m = q.get()
。
没有其他答案涵盖此方法,因此:
我发现到目前为止,最有用,最简单,最可靠的方法是询问您的数据库。例如,在Linux for Postgres上,您可以执行以下操作:
sudo su postgres
tail -f /var/log/postgresql/postgresql-8.4-main.log
每个数据库的过程将稍有不同。在数据库日志中,您不仅会看到原始SQL,还会看到django放置在系统上的任何连接设置或事务开销。
log_statement='all'
在postgresql.conf
了这个方法。
postgresql.conf
通过运行psql -U postgres -c 'SHOW config_file'
尽管您可以使用提供的代码来做到这一点,但我发现使用调试工具栏应用程序是显示查询的好工具。您可以从github 此处下载它。
这使您可以选择显示在给定页面上运行的所有查询以及查询所花费的时间。它还汇总了页面上的查询数量以及总时间,以便快速查看。当您想了解Django ORM在幕后的工作时,这是一个很棒的工具。它还具有许多其他不错的功能,您可以根据需要使用。
另一个选项,请参阅本文描述的settings.py中的日志记录选项
http://dabapps.com/blog/logging-sql-queries-django-13/
debug_toolbar减慢了开发服务器上的每个页面加载速度,而日志记录却没有,因此速度更快。可以将输出转储到控制台或文件中,因此UI不太好。但是对于包含大量SQL的视图,由于每个页面加载速度都很慢,因此通过debug_toolbar调试和优化SQL可能会花费很长时间。
如果您确定settings.py文件具有:
django.core.context_processors.debug
列于 CONTEXT_PROCESSORS
DEBUG=True
IP
在INTERNAL_IPS
元组中然后,您应该可以访问该sql_queries
变量。我在每个页面上都添加一个页脚,如下所示:
{%if sql_queries %}
<div class="footNav">
<h2>Queries</h2>
<p>
{{ sql_queries|length }} Quer{{ sql_queries|pluralize:"y,ies" }}, {{sql_time_sum}} Time
{% ifnotequal sql_queries|length 0 %}
(<span style="cursor: pointer;" onclick="var s=document.getElementById('debugQueryTable').style;s.disp\
lay=s.display=='none'?'':'none';this.innerHTML=this.innerHTML=='Show'?'Hide':'Show';">Show</span>)
{% endifnotequal %}
</p>
<table id="debugQueryTable" style="display: none;">
<col width="1"></col>
<col></col>
<col width="1"></col>
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">SQL</th>
<th scope="col">Time</th>
</tr>
</thead>
<tbody>
{% for query in sql_queries %}
<tr class="{% cycle odd,even %}">
<td>{{ forloop.counter }}</td>
<td>{{ query.sql|escape }}</td>
<td>{{ query.time }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
我sql_time_sum
通过添加行来获取变量
context_extras['sql_time_sum'] = sum([float(q['time']) for q in connection.queries])
到django_src / django / core / context_processors.py中的调试功能。
我为此目的开发了一个扩展,因此您可以轻松地在视图函数上放置装饰器,并查看执行了多少查询。
安装:
$ pip install django-print-sql
用作上下文管理器:
from django_print_sql import print_sql
# set `count_only` to `True` will print the number of executed SQL statements only
with print_sql(count_only=False):
# write the code you want to analyze in here,
# e.g. some complex foreign key lookup,
# or analyzing a DRF serializer's performance
for user in User.objects.all()[:10]:
user.groups.first()
用作装饰器:
from django_print_sql import print_sql_decorator
@print_sql_decorator(count_only=False) # this works on class-based views as well
def get(request):
# your view code here
我相信如果使用PostgreSQL,这应该可以工作:
from django.db import connections
from app_name import models
from django.utils import timezone
# Generate a queryset, use your favorite filter, QS objects, and whatnot.
qs=models.ThisDataModel.objects.filter(user='bob',date__lte=timezone.now())
# Get a cursor tied to the default database
cursor=connections['default'].cursor()
# Get the query SQL and parameters to be passed into psycopg2, then pass
# those into mogrify to get the query that would have been sent to the backend
# and print it out. Note F-strings require python 3.6 or later.
print(f'{cursor.mogrify(*qs.query.sql_with_params())}')
以下代码基于https://code.djangoproject.com/ticket/17741将查询作为有效SQL返回:
def str_query(qs):
"""
qs.query returns something that isn't valid SQL, this returns the actual
valid SQL that's executed: https://code.djangoproject.com/ticket/17741
"""
cursor = connections[qs.db].cursor()
query, params = qs.query.sql_with_params()
cursor.execute('EXPLAIN ' + query, params)
res = str(cursor.db.ops.last_executed_query(cursor, query, params))
assert res.startswith('EXPLAIN ')
return res[len('EXPLAIN '):]
我做了一个小片段,您可以使用:
from django.conf import settings
from django.db import connection
def sql_echo(method, *args, **kwargs):
settings.DEBUG = True
result = method(*args, **kwargs)
for query in connection.queries:
print(query)
return result
# HOW TO USE EXAMPLE:
#
# result = sql_echo(my_method, 'whatever', show=True)
它以参数函数(包含sql查询)作为参数,并检查调用该函数所需的args,kwargs。结果,它返回什么函数返回并在控制台中打印SQL查询。
我将此功能放在项目中一个应用程序的util文件中:
import logging
import re
from django.db import connection
logger = logging.getLogger(__name__)
def sql_logger():
logger.debug('TOTAL QUERIES: ' + str(len(connection.queries)))
logger.debug('TOTAL TIME: ' + str(sum([float(q['time']) for q in connection.queries])))
logger.debug('INDIVIDUAL QUERIES:')
for i, query in enumerate(connection.queries):
sql = re.split(r'(SELECT|FROM|WHERE|GROUP BY|ORDER BY|INNER JOIN|LIMIT)', query['sql'])
if not sql[0]: sql = sql[1:]
sql = [(' ' if i % 2 else '') + x for i, x in enumerate(sql)]
logger.debug('\n### {} ({} seconds)\n\n{};\n'.format(i, query['time'], '\n'.join(sql)))
然后,在需要时,我将其导入并从任何需要的上下文(通常是视图)中调用它,例如:
# ... other imports
from .utils import sql_logger
class IngredientListApiView(generics.ListAPIView):
# ... class variables and such
# Main function that gets called when view is accessed
def list(self, request, *args, **kwargs):
response = super(IngredientListApiView, self).list(request, *args, **kwargs)
# Call our function
sql_logger()
return response
最好在模板之外执行此操作,因为这样,如果您具有API视图(通常是Django Rest Framework),那么它也适用于该视图。
对于Django 2.2:
因为使用时大多数答案对我没有多大帮助./manage.py shell
。终于我找到了答案。希望这对某人有帮助。
要查看所有查询:
from django.db import connection
connection.queries
要查看单个查询的查询:
q=Query.objects.all()
q.query.__str__()
q.query
只是为我展示对象。使用__str__()
(字符串表示形式)显示完整查询。