データベースインストルメンテーション—Djangoドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/topics/db/instrumentation
移動先:案内検索

データベースインストルメンテーション

コードによって発行されたクエリを理解して制御できるように、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 –呼び出し可能。クエリを実行するために残りのパラメーターとともに呼び出す必要があります。
  • sqlstr、データベースに送信される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つの引数を取る呼び出し可能オブジェクトです。 これは、引数executesqlparamsmany、および [を使用して、コンテキストマネージャーのスコープ内のすべてのクエリ実行に対して呼び出されます。 X143X]上記のとおり。 execute(sql, params, many, context)を呼び出し、その呼び出しの戻り値を返すことが期待されています。