是否有一种方法可以在执行查询时显示Django正在运行的SQL ?


当前回答

请参阅文档常见问题:“如何查看Django正在运行的原始SQL查询?”

django.db.connection.queries包含一个SQL查询列表:

from django.db import connection
print(connection.queries)

queryset也有一个包含要执行的查询的query属性:

print(MyModel.objects.filter(name="my name").query)

注意,查询的输出不是有效的SQL,因为:

Django从未真正插入参数:它将查询和参数分别发送到数据库适配器,由数据库适配器执行适当的操作。

来自Django错误报告#17741。

因此,不应该将查询输出直接发送到数据库。

如果你需要重置查询,例如,查看在给定的时间内有多少查询在运行,你可以使用reset_queries from django.db:

from django.db import reset_queries
from django.db import connection

reset_queries()
# Run your query here
print(connection.queries)
>>> []

其他回答

请参阅文档常见问题:“如何查看Django正在运行的原始SQL查询?”

django.db.connection.queries包含一个SQL查询列表:

from django.db import connection
print(connection.queries)

queryset也有一个包含要执行的查询的query属性:

print(MyModel.objects.filter(name="my name").query)

注意,查询的输出不是有效的SQL,因为:

Django从未真正插入参数:它将查询和参数分别发送到数据库适配器,由数据库适配器执行适当的操作。

来自Django错误报告#17741。

因此,不应该将查询输出直接发送到数据库。

如果你需要重置查询,例如,查看在给定的时间内有多少查询在运行,你可以使用reset_queries from django.db:

from django.db import reset_queries
from django.db import connection

reset_queries()
# Run your query here
print(connection.queries)
>>> []

另一个选项,请参阅本文中描述的settings.py中的日志记录选项

http://dabapps.com/blog/logging-sql-queries-django-13/

Debug_toolbar会降低开发服务器上每个页面的加载速度,而日志记录则不会,因此速度更快。输出可以转储到控制台或文件,所以UI不是很好。但是对于包含大量sql的视图,通过debug_toolbar调试和优化sql可能需要很长时间,因为每个页面加载都非常慢。

这里已经有几个很好的答案了。

还有一种方法。

在测试中,这样做:

with self.assertNumQueries(3):
    response = self.client.post(reverse('payments:pay_list'))
    # or whatever

如果查询数量错误,则测试失败,并在控制台中打印所有原始SQL查询。

此外,此类测试有助于控制SQL查询的数量不会随着代码的更改而增加,并且数据库负载不会过多。

下面基于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 '):]

如果您需要为一些自定义SQL重用查询,还有另一种非常有用的方法。我曾在一个分析应用程序中使用过这种方法,它远远超出了Django的ORM所能轻松完成的范围,所以我将ORM生成的SQL作为子查询包含进来。

from django.db import connection
from myapp.models import SomeModel

queryset = SomeModel.objects.filter(foo='bar')

sql_query, params = queryset.query.as_sql(None, connection)

这将为您提供带有占位符的SQL,以及可以使用的带有查询参数的元组。你可以直接把它传递给DB:

with connection.connection.cursor(cursor_factory=DictCursor) as cursor:
    cursor.execute(sql_query, params)
    data = cursor.fetchall()