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

#1 楼

请参阅文档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。因此,您不应该将查询输出直接发送到数据库。

评论


为了将来证明此答案,您应该链接Django文档的当前版本:docs.djangoproject.com/en/dev/faq/models/…

–安德烈·米勒(Andre Miller)
09年7月2日在13:31

好答案。但是,建议使用指定的内置Pythonian str()函数,该函数调用内部__str __()方法。例如str(MyModel.objects.filter(name =“ my name”)。query)我也建议使用IPython和项目的Django Shell。制表符补全然后提供对象自省。由于Django以其可靠的命名方案而闻名,因此这种方法趋向于非常有用。

–洛伦茨·罗索尔(Lorenz Lo Sauer)
13年7月24日在5:55

请注意,查询的输出不是有效的SQL,因为“ Django从未实际内插参数:它会将查询和参数分别发送到数据库适配器,后者执行适当的操作。”资料来源:code.djangoproject.com/ticket/17741

– Gregoltsov
2014年7月7日14:51

@AndreMiller您应该使用稳定的而不是dev来链接到当前版本的Django,如下所示:docs.djangoproject.com/en/stable/faq/models/…

– Flimm
17年4月4日在14:35

django.db.connection.queries返回空列表

–庆典
19年8月5日在13:21

#2 楼

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>


评论


我将它与--print-sql或SHELL_PLUS_PRINT_SQL = True结合使用,但没有帮助-我仍然看不到查询。知道为什么吗? Django 1.8

– Dejell
17年5月16日在9:43



您需要在settings.py中设置DEBUG = True才能查看查询

–康斯坦丁·沃斯切诺夫(Konstantin Voschanov)
19/12/11在13:02

#3 楼

请看一下debug_toolbar,它对于调试非常有用。

文档和源可在http://django-debug-toolbar.readthedocs.io/上找到。



评论


当查询因SQL语法错误而失败时,debug_toolbar尤其有用。它将显示最后一个尝试运行(失败)的查询,从而更易于调试。

–scoopseven
2012年8月16日在17:20

唯一的事情是您在浏览器上看到SQL查询。如果您从终端运行测试并希望在那里看到它,那么这不是可行的解决方案。仍然很棒,直到今天我一直在使用它。

– Erdin Eray
19/12/5在12:47

#4 楼

q = Query.objects.values('val1','val2','val_etc')

print q.query


评论


很简单的答案!好啊

– Espoir Murhabazi
19年7月17日在10:13

此功能是否已删除?当我执行m = MyModel.objects.get(...)后跟m.query时,它不起作用

– g
19/12/20在19:23

这是因为m不再是查询集。使用q = MyModel.objects.filter(...),然后使用q.query,然后使用m = q.get()。

–浏览器
20 May 18 '15:11

#5 楼

没有其他答案可以涵盖此方法,因此:

我发现到目前为止,最有用,最简单,最可靠的方法是询问您的数据库。例如,在Linux for Postgres上,您可以执行以下操作:

sudo su postgres
tail -f /var/log/postgresql/postgresql-8.4-main.log


每个数据库的过程稍有不同。在数据库日志中,您不仅会看到原始SQL,而且还会看到django放置在系统上的任何连接设置或事务开销。

评论


不要忘记在postgresql.conf中为此方法设置log_statement ='all'。

– RickyA
16-2-22在11:33

您可以通过运行psql -U postgres -c'SHOW config_file'找到postgresql.conf。

– kramer65
19年10月1日在7:23

#6 楼

尽管您可以使用提供的代码来做到这一点,但我发现使用调试工具栏应用程序是显示查询的好工具。您可以从github此处下载它。

这使您可以选择显示在给定页面上运行的所有查询以及查询所花费的时间。它还汇总了页面上的查询数量以及总时间,以便快速查看。当您想了解Django ORM在幕后所做的工作时,这是一个很棒的工具。它还具有很多其他不错的功能,如果您愿意,可以使用。

评论


在我看来这是最好的版本:github.com/django-debug-toolbar/django-debug-toolbar

– philfreo
2012年1月26日21:52

#7 楼

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

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

debug_toolbar减慢了开发服务器上的每个页面加载速度,而日志记录却没有,因此速度更快。可以将输出转储到控制台或文件中,因此UI不太好。但是对于包含大量SQL的视图,由于每个页面加载速度都很慢,因此通过debug_toolbar调试和优化SQL可能会花费很长时间。

评论


优秀的!虽然工具栏看起来不错,但我认为这个答案应该是公认的。这是我想要的解决方案,因为它允许“ manage.py runserver”将SQL记录到控制台,并且可以与“ manage.py migration”一起使用。后者让我看到在创建表时绝对没有设置“在删除级联上”。值得注意的是,该答案基于docs.djangoproject.com/en/1.9/topics/logging / ...

– Lance E Sloan先生
16-3-11在17:41



#8 楼

如果确定您的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中的调试功能。

评论


我只是尝试了一下,并且(删除了sql_time_sum部分)得到了:模板中没有命名循环。 “奇偶”未定义-我想念什么?

–castaway
17年8月15日在9:45

#9 楼

我为此目的开发了一个扩展,因此您可以轻松在视图函数上放置装饰器,并查看执行了多少查询。

要安装:

$ 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

#10 楼

仅在django中添加,如果您有类似以下的查询:

MyModel.objects.all()


做:

MyModel.objects.all().query.sql_with_params()


获取sql字符串

#11 楼

我相信如果使用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())}')


评论


即使在Python 2中也可以使用。仅需要像print(cursor.mogrify(* qs.query.sql_with_params()))这样的重构。

– iChux
18-10-25在9:14

IIRC Cursor.mogrify返回一个字符串,因此我认为使用f字符串进行格式化是多余的。

–钱德
18-10-25在14:24

#12 楼

我将此功能放在项目中一个应用程序的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),那么它也适用于此。

#13 楼

以下代码基于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 '):]


#14 楼

我制作了一个小片段供您使用:

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查询。

#15 楼

对于Django 2.2:

由于使用./manage.py shell时,大多数答案对我没有多大帮助。终于我找到了答案。希望这对某人有帮助。

查看所有查询:

from django.db import connection
connection.queries


查看单个查询的查询:

q=Query.objects.all()
q.query.__str__()


q.query只是为我显示对象。
使用__str__()(字符串表示形式)显示完整的查询。

#16 楼

使用django.db.connection.queries查看查询

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


访问QuerySet对象上的原始SQL查询

 qs = MyModel.objects.all()
 print(qs.query)