データベースの計測¶
コードから発行されたクエリを理解して制御するために、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 is a callable taking five arguments. It is called for every query
execution in the scope of the context manager, with arguments execute,
sql, params, many, and context as described above. It's
expected to call execute(sql, params, many, context) and return the return
value of that call.