如何查看Django正在运行的原始SQL查询?

455
有没有办法在执行查询时显示Django正在运行的SQL语句?

https://dev59.com/Gqrns4cB2Jgan1zngCsO#23000580 - Luke Dupin
26个回答

568

请查看文档中的常见问题解答: "如何查看 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.db中的reset_queries

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

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

19
为了未来的考虑,您应该链接Django当前版本的文档:http://docs.djangoproject.com/en/dev/faq/models/#how-can-i-see-the-raw-sql-queries-django-is-running - Andre Miller
8
很棒的回答。不过,建议使用指定的内置Python str()函数,它调用内部的__str __()方法。例如:str(MyModel.objects.filter(name="my name").query)我还建议使用IPython和你项目中的Django shell。通过制表符完成可以提供对象内省。由于Django以自己的规范命名而著称,所以这种方法通常非常有用。 - Lorenz Lo Sauer
9
请注意,query的输出结果并不是有效的SQL语句,因为“Django从未实际插值参数:它会将查询和参数分别发送到数据库适配器中,后者会执行适当的操作。”来源:https://code.djangoproject.com/ticket/17741 - gregoltsov
6
你应该使用 stable 而不是 dev 来链接到 Django 的当前版本,像这样:https://docs.djangoproject.com/en/stable/faq/models/#how-can-i-see-the-raw-sql-queries-django-is-running - Flimm
3
django.db.connection.queries返回空列表 - Fantastory
显示剩余6条评论

114

Django-extensions有一个命令shell_plus,其中包含一个print-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>

1
我正在使用 --print-sql 或 SHELL_PLUS_PRINT_SQL = True,但它并没有帮助 - 我仍然无法看到查询。有任何想法吗?django 1.8 - Dejell
2
你需要在settings.py中设置DEBUG = True才能查看查询。 - Konstantin Voschanov
这个答案简直是救星。 - rustyshackleford
是的,也许不是原po需要的答案,但对于我所需的事情非常有效。 - Paul Watson

71

3
debug_toolbar在遇到SQL语法错误导致查询失败时特别有用;它会显示最后一次尝试运行(并失败)的查询,从而更容易进行调试。 - scoopseven
1
唯一的问题是你在浏览器上看到了SQL查询。如果你从终端运行测试并希望在那里看到它,这不是一个可行的解决方案。尽管如此,它仍然很棒,我一直在使用它至今。 - Eray Erdin
如果在 Docker 中运行,则所有查询都显示为“None”。 - EugZol
1
@EugZol,请看一下这里,在设置INTERNAL_IPS时提到了Docker,也许会有所帮助。 - Bilal
它似乎没有显示除SELECT之外的任何其他查询。有办法启用它们吗? - blitz

41

查询实际上是嵌入在模型 API 中的:

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

print(q.query)

这个功能被移除了吗?当我执行 m = MyModel.objects.get(...) 然后执行 m.query 时它不起作用。 - s g
2
那是因为m不再是一个queryset了。使用q=MyModel.objects.filter(...),然后q.query,然后m=q.get() - Brouwer

35

没有其他答案涵盖了这种方法,所以:

我发现迄今为止最有用、简单和可靠的方法是向您的数据库询问。例如,在Linux上使用Postgres,您可以这样做:

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

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


9
别忘了在 postgresql.conf 中设置 log_statement='all' 以使用这种方法。 - RickyA
3
您可以通过运行psql -U postgres -c 'SHOW config_file'来查找您的 postgresql.conf 文件。 - kramer65

21
这是一个相对较晚的回答,但对于那些通过搜索到达这里的其他人来说可能仍然有用。我想介绍一种非常简单的日志记录方法; 在settins.py中添加django.db.backends记录器。
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'level': 'DEBUG',
        },
    },
}

我也使用一个环境变量来设置日志级别。因此,当我想查看SQL查询时,只需设置环境变量,调试日志将显示实际的查询语句。


18
虽然你可以使用提供的代码来完成,但我发现使用调试工具栏应用程序是一个很好的工具来显示查询。你可以从github 这里下载它。
这个工具可以让你选择显示在给定页面上运行的所有查询,以及查询所花费的时间。它还总结了页面上的查询数量以及总时间,以便快速查看。当你想要查看Django ORM在幕后执行的操作时,这是一个很好的工具。它还有很多其他的好功能,如果你喜欢的话,你也可以使用。

3
我会尽力为您翻译:对我来说,这似乎是最好的版本:https://github.com/django-debug-toolbar/django-debug-toolbar - philfreo

18

另一个选择是,在设置文件settings.py中查看此帖子描述的日志选项。

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

debug_toolbar会减缓开发服务器上每个页面的加载速度,而日志不会,所以它更快。输出可以转储到控制台或文件中,因此UI不如debug_toolbar那样好看。但对于具有大量SQL的视图,通过debug_toolbar调试和优化SQL可能需要很长时间,因为每个页面的加载速度都非常慢。


太好了!虽然工具栏看起来很棒,但我认为这个答案应该被接受。这是我想要的解决方案,因为它允许“manage.py runserver”将SQL记录到控制台,并且可以与“manage.py migrate”一起使用。后者让我看到当创建我的表时,“on delete cascade”绝对没有被设置。值得注意的是,这个答案基于https://docs.djangoproject.com/en/1.9/topics/logging/#django-db-backends。 - Mr. Lance E Sloan

12
我为此目的开发了一个扩展,因此您可以轻松地在您的视图函数上放置一个装饰器,并查看执行了多少个查询。
安装方法如下:
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: django-print-sql

我喜欢这个想法!我尝试了一下,但是它在创建或更新对象时没有添加查询,对吧? - physicalattraction
1
是的,目前仅支持读取查询,我还没有真正维护这个项目。 插入、更新和删除在不同的编译器中,django.db.models.sql.compiler.SQLInsertCompiler/SQLUpdateCompiler/SQLDeleteCompiler。我可能很快会添加计数功能。或者欢迎您做出贡献 :D - rabbit.aaron

11
如果您确保您的settings.py文件包含以下内容:
  1. django.core.context_processors.debug列在CONTEXT_PROCESSORS
  2. DEBUG=True
  3. 您的IPINTERNAL_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中的debug函数。


1
我刚试了一下,(已经删除了sql_time_sum部分),得到了:模板中没有命名循环。'odd,even'未定义 - 我错过了什么? - castaway

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接