# Django 5.0.9.dev20240806133106 ドキュメント

# データベースの計測

コードから発行されたクエリを理解して制御するために、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)` を呼び出して、その戻り値を返すことが期待されます。