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


当前回答

我为此开发了一个扩展,所以你可以很容易地在你的视图函数上放一个装饰器,看看有多少查询被执行了。

如何安装:

$ 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

Github: https://github.com/rabbit-aaron/django-print-sql

其他回答

我相信这应该工作,如果你使用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())}')

django扩展有一个带参数print-sql的命令shell_plus

./manage.py shell_plus --print-sql

在django-shell中,所有执行的查询都会被打印出来

Ex.:

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>
from django.db import reset_queries, connection
class ShowSQL(object):
    def __enter__(self):
        reset_queries()
        return self

    def __exit__(self, *args):
        for sql in connection.queries:
            print('Time: %s\nSQL: %s' % (sql['time'], sql['sql']))

然后你可以使用:

with ShowSQL() as t:
    some queries <select>|<annotate>|<update> or other 

它打印

时间:% s SQL: % s

如果您需要为一些自定义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()

请参阅文档常见问题:“如何查看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)
>>> []