Djangoが実行している生のSQLクエリを確認するにはどうすればよいですか?


307

クエリの実行中にDjangoが実行しているSQLを表示する方法はありますか?

回答:


372

docs 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から

そのため、クエリ出力をデータベースに直接送信しないでください。


13
この答えを将来的に証明するには、現在のバージョンのDjangoのドキュメントをリンクする必要があります:docs.djangoproject.com/en/dev/faq/models/…–
Andre Miller

5
すばらしい答えです。ただし、str()内部__str__()メソッドを呼び出す指定の組み込みPythonian 関数を使用することをお勧めします。たとえばstr(MyModel.objects.filter(name="my name").query) 、プロジェクトのIPythonとDjangoシェルを使用することもお勧めします。その後、タブ補完はオブジェクトのイントロスペクションを提供します。Djangoはその断定的な命名方式で知られているため、この方法論は非常に役立つ傾向があります。
Lorenz Lo Sauer 2013

7
の出力queryは有効なSQL ではないことに注意してください。「Djangoが実際にパラメーターを補間することはありません。適切な操作を実行するデータベースアダプターにクエリとパラメーターを個別に送信します。」出典:code.djangoproject.com/ticket/17741
gregoltsov 2014

3
@AndreMiller次のように、Djangoの現在のバージョンにリンクするstableにはdev、ではなくを使用する必要があります。docs.djangoproject.com / en
stable

3
django.db.connection.queriesは空のリストを返します
ファンタスティック

61

Django拡張機能には、パラメーター付きのコマンド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
デジェル

1
クエリを表示するには、settings.pyでDEBUG = Trueを設定する必要があります
Konstantin Voschanov

50

debug_toolbarを見てください。デバッグに非常に役立ちます。

ドキュメントとソースはhttp://django-debug-toolbar.readthedocs.io/から入手できます

デバッグツールバーのスクリーンショット


1
debug_toolbarは、SQL構文エラーで失敗するクエリがある場合に特に役立ちます。実行を試みた(および失敗した)最後のクエリが表示され、デバッグが容易になります。
scoopseven

唯一のものは、ブラウザにSQLクエリが表示されることです。端末からテストを実行し、そこで確認したい場合、これは実行可能なソリューションではありません。まだ素晴らしいです、私は今日までそれを使用しています。
Erdin Eray

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

print q.query

とてもシンプルな答え!ニース
エスポワールムルハバジ

この機能は削除されましたか?私がm = MyModel.objects.get(...)続いたときにそれは機能しませんm.query
sg

これmは、がクエリセットではなくなったためです。使用q = MyModel.objects.filter(...)、そしてq.query、それからm = q.get()
Brouwer

24

他の答えはこの方法をカバーしていないので、

私は断然、最も便利でシンプルで信頼できる方法は、データベースに問い合わせることです。たとえば、Linux for Postgresでは次のようにします。

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

データベースごとに手順が少し異なります。データベースログには、生のSQLだけでなく、接続のセットアップやジャンゴがシステムに課しているトランザクションのオーバーヘッドも表示されます。


8
このメソッドに設定log_statement='all'することを忘れないでくださいpostgresql.conf
RickyA 2016

2
あなたは、あなたを見つけることができますpostgresql.conf実行してpsql -U postgres -c 'SHOW config_file'
kramer65

17

提供されたコードでそれを行うことができますが、デバッグツールバーアプリを使用すると、クエリを表示するための優れたツールであることがわかります。こちらの githubからダウンロードできます。

これにより、特定のページで実行されたすべてのクエリと、クエリにかかった時間を表示するオプションが提供されます。また、簡単なレビューのために、ページ上のクエリ数と合計時間を合計します。これは、Django ORMが舞台裏で行うことを確認したい場合に最適なツールです。また、必要に応じて使用できる他の多くの優れた機能も備えています。


2
これが最高のバージョンであるように私に見えます:github.com/django-debug-toolbar/django-debug-toolbar
philfreo

15

別のオプション、この投稿で説明されているsettings.pyのロギングオプションを参照してください

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

debug_toolbarは、開発サーバーでの各ページの読み込みを遅くしますが、ロギングはそうではないので、より高速です。出力はコンソールまたはファイルにダンプできるため、UIはそれほど良くありません。ただし、多くのSQLを含むビューの場合、各ページの読み込みが非常に遅いため、debug_toolbarを使用してSQLをデバッグおよび最適化するのに長い時間がかかる可能性があります。


優れた!ツールバーの見栄えは良いですが、この答えは受け入れられるべきだと思います。これは、「manage.py runserver」がSQLをコンソールに記録し、「manage.py migrate」で機能するため、私が欲しかったソリューションです。後者を使用すると、テーブルの作成時に「削除カスケード」が設定されていなかったことがわかります。この回答はdocs.djangoproject.com/en/1.9/topics/logging/…に
LS

10

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のデバッグ関数に追加します。


1
私はこれを試したところ、(sql_time_sumの部分を削除して)、テンプレートに名前付きサイクルがありませんでした。「奇数、偶数」は定義されていません-何が欠けていますか?
キャスタウェイ2017

8

この目的で拡張機能を開発したので、ビュー関数にデコレータを簡単に配置して、実行されるクエリの数を確認できます。

インストールするには:

$ 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


3

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 2018年

私はフォーマットするためのF列の使用を想定してIIRC Cursor.mogrifyは...余計で、文字列を返す
のChanderは

2

以下は、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 '):]

2

私はあなたが使える小さなスニペットを作りました:

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クエリを含む)を引数に取り、その関数を呼び出すために必要なkwargsを引数に取ります。結果として、関数が返すものを返し、SQLクエリをコンソールに出力します。


1

この関数をプロジェクトのアプリの1つの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)がある場合、テンプレートにも適用できるため、テンプレートの外でこれを行うと便利です。


1

Django 2.2の場合:

を使用するとき、ほとんどの回答は私にとってあまり役に立ちませんでした./manage.py shell。最後に私は答えを見つけました。これが誰かに役立つことを願っています。

すべてのクエリを表示するには:

from django.db import connection
connection.queries

1つのクエリのクエリを表示するには:

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

q.queryオブジェクトを表示するだけです。__str__()(文字列表現)を使用すると、完全なクエリが表示されます。


0

django.db.connection.queriesを使用してクエリ表示する

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

QuerySetオブジェクトの生のSQLクエリにアクセスする

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

0

追加するだけで、djangoで次のようなクエリがある場合:

MyModel.objects.all()

行う:

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

SQL文字列を取得する

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.