[Dd]enzow(ill)? with DB and Python

DBとか資格とかPythonとかの話をつらつらと

Djangoで実行されたクエリを確認したい(`connection.queries`)

connection.queriesで発行されたSQLを確認できるというDjangoの小ネタです。

DjangoのORMで発行されるSQLはQuerySetであれば以下のように確認できます。

In [1]: from myapp.models import Product

In [2]: print(Product.objects.filter(id=1).query)
SELECT "myapp_product"."id", "myapp_product"."name", "myapp_product"."price" FROM "myapp_product" WHERE "myapp_product"."id" = 1

しかし、この方法では都度.queryで確認しなければいけない上に、saveなどのDML系の処理についてはSQLを確認できません。

他の方法として、一連の処理で発行されたSQLをすべて確認するのであればDB側で確認する手もあります。(MySQLのGeneralログなど) しかし、DjangoにはDBへのコネクションを介して発行されたSQLをすべて確認する方法もあります。それにはconnections.queriesを使用します。

In [1]: from django.db import connection

In [2]: from myapp.models import Product, ProductOrder

In [3]: Product.objects.filter(id=1).count()
Out[3]: 0

In [4]: list(ProductOrder.objects.filter(id=1))
Out[4]: []

In [5]: for history in connection.queries:
   ...:     print(history)
   ...:
{'sql': 'SELECT COUNT(*) AS "__count" FROM "myapp_product" WHERE "myapp_product"."id" = 1', 'time': '0.001'}
{'sql': 'SELECT "myapp_productorder"."id", "myapp_productorder"."product_id", "myapp_productorder"."amount", "myapp_productorder"."order_date" FROM "myapp_productorder" WHERE "myapp_productorder"."id" = 1', 'time': '0.000'}

このように発行されたSQL文と実行時間が記録されています。例ではSELECTだけですが、savedeleteで発行されたDMLについても記録されます。

また、この結果を途中でクリアする場合はreset_queriesを使用します。

In [6]: from django.db import reset_queries

In [7]: len(connection.queries)
Out[7]: 2

In [8]: len(connection.queries)  # 一度取得しても結果はクリアされない
Out[8]: 2

In [10]: reset_queries()

In [11]: len(connection.queries)  # 結果がクリアされている
Out[11]: 0

なかなか便利ですが、settings.DEBUGTrueの時しか記録されないのが残念ですね。用途を考えればあたりまではありますが・・・