Skip to content
16 changes: 14 additions & 2 deletions debug_toolbar/panels/sql/tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
from time import perf_counter

import django.test.testcases
from django.apps import apps
from django.utils.encoding import force_str

from debug_toolbar import settings as dt_settings
from debug_toolbar.utils import get_stack_trace, get_template_info

try:
Expand All @@ -28,6 +30,11 @@
allow_sql = contextvars.ContextVar("debug-toolbar-allow-sql", default=True)


DDT_MODELS = {
m._meta.db_table for m in apps.get_app_config("debug_toolbar").get_models()
}


class SQLQueryTriggered(Exception):
"""Thrown when template panel triggers a query"""

Expand Down Expand Up @@ -224,8 +231,13 @@ def _record(self, method, sql, params):
}
)

# We keep `sql` to maintain backwards compatibility
self.logger.record(**kwargs)
# Skip tracking for DDT models by default.
# This can be overridden by setting TRACK_DDT_MODELS = True
if dt_settings.get_config()["TRACK_DDT_MODELS"] or not any(
table in sql for table in DDT_MODELS
):
# We keep `sql` to maintain backwards compatibility
self.logger.record(**kwargs)

def callproc(self, procname, params=None):
return self._record(super().callproc, procname, params)
Expand Down
1 change: 1 addition & 0 deletions debug_toolbar/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def _is_running_tests():
"ROOT_TAG_EXTRA_ATTRS": "",
"SHOW_COLLAPSED": False,
"SHOW_TOOLBAR_CALLBACK": "debug_toolbar.middleware.show_toolbar",
"TRACK_DDT_MODELS": False,
# Panel options
"EXTRA_SIGNALS": [],
"ENABLE_STACKTRACES": True,
Expand Down
53 changes: 53 additions & 0 deletions tests/panels/test_sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from django.test.utils import override_settings

import debug_toolbar.panels.sql.tracking as sql_tracking
from debug_toolbar.models import HistoryEntry
from debug_toolbar.panels.sql import SQLPanel

try:
Expand All @@ -33,6 +34,18 @@ def sql_call(*, use_iterator=False):
return list(qs)


def sql_call_ddt():
"""Helper function to query one of the DDT models to test tracking of DDT entries."""
qs = HistoryEntry.objects.all()
return list(qs)


async def async_sql_call_ddt():
"""(async) Helper function to query one of the DDT models to test tracking of DDT entries."""
qs = HistoryEntry.objects.all()
return await sync_to_async(list)(qs)


async def async_sql_call(*, use_iterator=False):
qs = User.objects.all()
if use_iterator:
Expand Down Expand Up @@ -104,6 +117,46 @@ async def test_recording_concurrent_async(self):
# ensure the stacktrace is populated
self.assertTrue(len(query["stacktrace"]) > 0)

@override_settings(DEBUG_TOOLBAR_CONFIG={"TRACK_DDT_MODELS": True})
def test_ddt_models_tracked(self):
"""test if DDT models are being tracked when the `TRACK_DDT_MODELS` is set to True"""
self.assertEqual(len(self.panel._queries), 0)

sql_call_ddt()

# ensure query was logged
self.assertEqual(len(self.panel._queries), 1)
query = self.panel._queries[0]
self.assertTrue(HistoryEntry._meta.db_table in query["sql"])

@override_settings(DEBUG_TOOLBAR_CONFIG={"TRACK_DDT_MODELS": True})
async def test_ddt_models_tracked_async(self):
"""(async) test if DDT models are being tracked when the `TRACK_DDT_MODELS` is set to True"""
self.assertEqual(len(self.panel._queries), 0)

await async_sql_call_ddt()

# ensure query was logged
self.assertEqual(len(self.panel._queries), 1)
query = self.panel._queries[0]
self.assertTrue(HistoryEntry._meta.db_table in query["sql"])

def test_ddt_models_not_tracked(self):
"""Tests whether DDt models are not being tracked when the `TRACK_DDT_MODELS` is set to False"""
self.assertEqual(len(self.panel._queries), 0)

sql_call_ddt()

self.assertEqual(len(self.panel._queries), 0)

async def test_ddt_models_not_tracked_async(self):
"""(async) Tests whether DDt models are not being tracked when the `TRACK_DDT_MODELS` is set to False"""
self.assertEqual(len(self.panel._queries), 0)

await async_sql_call_ddt()

self.assertEqual(len(self.panel._queries), 0)

@unittest.skipUnless(
connection.vendor == "postgresql", "Test valid only on PostgreSQL"
)
Expand Down