# Documentation Django 5.2.8

# Instrumentation de base de données

Pour vous aider à comprendre et à contrôler les requêtes produites par votre code, Django fournit un point d’accès pour installer des fonctions enveloppantes autour de l’exécution des requêtes de base de données. Par exemple, ces fonctions peuvent compter les requêtes, mesurer leur durée, les journaliser ou même empêcher leur exécution (par ex. pour s’assurer qu’aucune requête ne soit exécutée lors du rendu d’un gabarit avec des données préchargées.

Les fonctions enveloppantes sont structurées comme pour les intergiciels – il s’agit d’objets exécutables qui acceptent un autre exécutable dans l’un de leurs paramètres. Elles appellent ce dernier pour invoquer la requête de base de données (potentiellement enveloppée), et elles peuvent faire ce qu’elles veulent autour de cet appel. Elles sont cependant créées et installées par le code utilisateur, ce qui fait qu’elles n’ont pas besoin d’une fabrique distincte comme pour les intergiciels.

L’installation d’une fonction enveloppante se fait dans un gestionnaire de contexte, ce qui rend ces fonctions temporaires et spécifiques à un certain flux de votre code.

Comme mentionné ci-dessus, un exemple de fonction enveloppante est un bloqueur d’exécution de requête. Voici à quoi cela pourrait ressembler

    def blocker(*args):
        raise Exception("No database access allowed here.")

Et cela serait utilisé dans une vue pour bloquer les requêtes provenant d’un gabarit, comme ceci

    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)

Les paramètres envoyés à la fonction enveloppante sont :

- `execute` – un objet exécutable, qui devrait être appelé avec le reste des paramètres afin d’exécuter la requête.

- `sql` – une chaîne `str`, la requête SQL qui sera envoyée à la base de données.

- `params` – une liste (ou tuple) de paramètres à destination de la commande SQL, ou une liste de listes si l’appel enveloppé est `executemany()`.

- `many` – une valeur booléenne indiquant si l’appel invoqué en définitive sera `execute()` ou `executemany()` (et si `params` doit être une liste de valeurs ou une liste de listes de valeurs).

- `context` – un dictionnaire avec des données supplémentaires sur le contexte de l’invocation. Cela inclut les éléments `connection` et `cursor`.

En utilisant les paramètres, une version à peine plus complexe du bloqueur pourrait inclure le nom de la connexion dans le message d’erreur

    def blocker(execute, sql, params, many, context):
        alias = context["connection"].alias
        raise Exception("Access to database '{}' blocked here".format(alias))

Pour un exemple plus complet, un journaliseur de requête pourrait ressembler à ceci

    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)

Pour utiliser cela, il faut créer un objet de journalisation et l’installer comme enveloppeur

    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)

Renvoie un gestionnaire de contexte qui, en entrée, installe la fonction d’enveloppement autour des exécutions de requêtes de base de données, et en sortie enlève cette fonction. La fonction d’enveloppement est installée sur l’objet connexion du fil d’exécution local.

`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.