Инструментарий базы данных¶
Чтобы помочь вам понять и контролировать запросы, выдаваемые вашим кодом, Django предоставляет хук для установки функций-оберток вокруг выполнения запросов к базе данных. Например, обёртки могут подсчитывать запросы, измерять длительность запросов, записывать запросы в журнал или даже предотвращать их выполнение (например, чтобы убедиться, что при рендеринге шаблона с предварительно собранными данными не будет выдано никаких запросов).
Обертки созданы по образцу middleware - они являются вызываемыми переменными, которые принимают другую вызываемую переменную в качестве одного из аргументов. Они вызывают эту вызываемую переменную, чтобы вызвать (возможно, обернутый) запрос к базе данных, и могут делать все, что хотят, вокруг этого вызова. Однако они создаются и устанавливаются пользовательским кодом и поэтому не нуждаются в отдельной фабрике, как промежуточное ПО.
Установка обертки выполняется в менеджере контекста - таким образом, обертки являются временными и специфичными для некоторого потока в вашем коде.
Как упоминалось выше, примером обертки является блокировщик выполнения запроса. Он может выглядеть следующим образом:
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
– astr
, SQL-запрос, который будет отправлен в базу данных.params
– список/кортеж значений параметров для SQL-команды, или список/кортеж списков/кортежей, если обернутый вызовexecutemany()
.many
–bool
, указывающий, является ли конечный вызванный вызовexecute()
илиexecutemany()
(и ожидается ли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)
Чтобы использовать его, необходимо создать объект logger и установить его в качестве обертки:
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
- это вызываемый модуль, принимающий пять аргументов. Он вызывается для каждого выполнения запроса в области действия контекстного менеджера с аргументами execute
, sql
, params
, many
и context
, как описано выше. Ожидается, что он вызовет execute(sql, params, many, context)
и вернет возвращаемое значение этого вызова.