データベースの計測¶
コードから発行されたクエリを理解して制御するために、Django は、データベースクエリの実行周辺にラッパー関数をインストールするためのフックを提供しています。たとえば、ラッパーは、クエリのカウント、クエリの実行時間の測定、クエリのログ、さらにクエリの実行の防止までもできます (たとえば、プリフェッチされたデータを使用してテンプレートをレンダリングする間にクエリが発行されないようにするため)。
ラッパーは ミドルウェア にならったもので、別の呼び出し可能オブジェクトを引数の1つとして受け取ります。ラッパーはデータベースクエリ(ラップされている可能性があります)を呼び出すために callable を呼び出します。しかし、これらはユーザーコードによって作成され、インストールされるため、ミドルウェアのように個別のファクトリを必要としません。
ラッパーのインストールは、コンテキストマネージャで行われます。そのため、ラッパーは一時的なもので、コード内の特定のフローに特化したものです。
前述したように、ラッパーの例はクエリ実行ブロッカーです。以下のようなものです:
def blocker(*args):
raise Exception("No database access allowed here.")
そして、テンプレートからのクエリをブロックするには、ビューでこのように使用します:
from django.db import connection
from django.shortcuts import render
def my_view(request):
context = {...} # Code to generate context with all data.
template_name = ...
with connection.execute_wrapper(blocker):
return render(request, template_name, context)
ラッパーに送られるパラメーターは以下の通りです:
execute
-- クエリを実行するために、残りのパラメータと一緒に呼び出される呼び出し可能オブジェクト。sql
-- データベースに送信する SQL クエリのstr
。params
-- SQL コマンドのパラメータ値のリストまたはタプル、または、ラップされた呼び出しがexecutemany()
の場合はリストまたはタプルのリストまたはタプル。many
-- 最終的に呼び出すのがexecute()
なのかexecutemany()
なのかを示すbool
(params
が値のシーケンスなのか、値のシーケンスのシーケンスなのかを示します)。context
-- 呼び出しのコンテキストに関するデータを含む辞書。これにはコネクションとカーソルが含まれます。
このパラメータを使用することで、次のように、もう少し複雑なバージョンのブロッカーで、エラーメッセージにコネクション名を含めることができます。
def blocker(execute, sql, params, many, context):
alias = context["connection"].alias
raise Exception("Access to database '{}' blocked here".format(alias))
より完全な例として、クエリロガーは次のようになります。
import time
class QueryLogger:
def __init__(self):
self.queries = []
def __call__(self, execute, sql, params, many, context):
current_query = {"sql": sql, "params": params, "many": many}
start = time.monotonic()
try:
result = execute(sql, params, many, context)
except Exception as e:
current_query["status"] = "error"
current_query["exception"] = e
raise
else:
current_query["status"] = "ok"
return result
finally:
duration = time.monotonic() - start
current_query["duration"] = duration
self.queries.append(current_query)
これを使用するには、ロガーオブジェクトを作成し、ラッパーとしてインストールします。
from django.db import connection
ql = QueryLogger()
with connection.execute_wrapper(ql):
do_queries()
# Now we can print the log.
print(ql.queries)
connection.execute_wrapper()
¶
- execute_wrapper(wrapper)¶
入力すると、データベースクエリ実行の周囲にラッパーをインストールし、終了するとラッパーを削除するコンテキストマネージャを返します。ラッパーはスレッドローカルのコネクションオブジェクトにインストールされます。
wrapper
は5つの引数を取る呼び出し可能オブジェクトです。 上記のように、 execute
, sql
, params
, many
, context
を引数として、コンテキストマネージャのスコープ内でクエリを実行するたびに呼び出されます。 execute(sql、params、many、context)
を呼び出して、その戻り値を返すことが期待されます。