データベースインストルメンテーション
コードによって発行されたクエリを理解して制御できるように、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
–str
、データベースに送信されるSQLクエリ。params
– SQLコマンドのパラメーター値のリスト/タプル、またはラップされた呼び出しがexecutemany()
の場合はリスト/タプルのリスト/タプル。many
–最終的に呼び出される呼び出しがexecute()
またはexecutemany()
のどちらであるか(およびparams
が次のシーケンスであると予想されるかどうか)を示すbool
値、または値のシーケンスのシーケンス)。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
、および [を使用して、コンテキストマネージャーのスコープ内のすべてのクエリ実行に対して呼び出されます。 X143X]上記のとおり。 execute(sql, params, many, context)
を呼び出し、その呼び出しの戻り値を返すことが期待されています。