~4 دقیقه مطالعه • بروزرسانی ۱۹ اسفند ۱۴۰۴
۱. مقدمه: Database Instrumentation در Django
Django یک قابلیت قدرتمند برای کنترل و بررسی کوئریهای دیتابیس ارائه میدهد. این قابلیت به شما اجازه میدهد wrapperهایی روی اجرای کوئریها نصب کنید تا:
- تعداد کوئریها را بشمارید
- مدت زمان اجرای هر کوئری را اندازه بگیرید
- کوئریها را لاگ کنید
- یا حتی اجرای کوئری را مسدود کنید
این wrapperها شبیه middleware هستند، اما مخصوص دیتابیس و فقط در محدودهٔ یک context manager فعال میشوند.
۲. ساختار کلی یک Wrapper
یک wrapper یک تابع یا callable است که پنج پارامتر دریافت میکند:
- execute: تابعی که باید برای اجرای واقعی کوئری فراخوانی شود
- sql: رشتهٔ SQL
- params: پارامترهای کوئری
- many: آیا executemany اجرا میشود؟
- context: اطلاعات اضافی شامل connection و cursor
۳. مثال ساده: مسدودکنندهٔ کوئری
def blocker(*args):
raise Exception("No database access allowed here.")
استفاده در view:
from django.db import connection
from django.shortcuts import render
def my_view(request):
context = {...}
template_name = ...
with connection.execute_wrapper(blocker):
return render(request, template_name, context)
نسخهٔ پیشرفتهتر با نام دیتابیس:
def blocker(execute, sql, params, many, context):
alias = context["connection"].alias
raise Exception(f"Access to database '{alias}' blocked here")
۴. مثال کامل: Query Logger
این logger مدت زمان اجرای هر کوئری، وضعیت و پارامترها را ثبت میکند.
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()
print(ql.queries)
۵. متد execute_wrapper
connection.execute_wrapper(wrapper) یک context manager برمیگرداند که:
- در زمان ورود، wrapper را فعال میکند
- در زمان خروج، آن را غیرفعال میکند
- فقط روی همان connection و همان thread اعمال میشود
Wrapper باید:
- تابع execute را فراخوانی کند
- نتیجهٔ آن را برگرداند
- در صورت نیاز رفتار را تغییر دهد
۶. کاربردهای رایج Wrapperها
- جلوگیری از اجرای کوئری در template (برای اطمینان از prefetch کامل)
- اندازهگیری مدت زمان کوئریها
- ثبت کوئریها برای تحلیل performance
- شبیهسازی خطاهای دیتابیس
- محدودکردن تعداد کوئریها (مثلاً در تستها)
جمعبندی
قابلیت execute_wrapper در Django ابزاری قدرتمند برای کنترل و تحلیل کوئریهای دیتابیس است. با استفاده از wrapperها میتوانید رفتار اجرای کوئریها را تغییر دهید، آنها را لاگ کنید، یا حتی اجرای آنها را مسدود کنید. این ابزار برای بهینهسازی، تست، مانیتورینگ و جلوگیری از کوئریهای ناخواسته بسیار مفید است.
نوشته و پژوهش شده توسط دکتر شاهین صیامی