chore(dev): add Django Debug Toolbar (dev-only, DEBUG+USE_SQLITE gated)

Double-gated install: only loads when DEBUG=true AND USE_SQLITE=true,
never in prod. Lets us profile SQL query counts on the dashboard and
payroll pages before attacking N+1 hotspots.

requirements.txt adds django-debug-toolbar==6.0.0
config/settings.py conditionally appends to INSTALLED_APPS + MIDDLEWARE
config/urls.py conditionally includes __debug__ route

No behavioural change to production.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Konrad du Plessis 2026-04-24 00:47:19 +02:00
parent 0c42cde4ff
commit 7075269a07
3 changed files with 52 additions and 2 deletions

View File

@ -300,3 +300,41 @@ if os.getenv('USE_SQLITE', 'false').lower() == 'true':
CSRF_COOKIE_SECURE = False
SESSION_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SAMESITE = 'Lax'
# === DEV-ONLY: Django Debug Toolbar ===
# Loaded ONLY when BOTH DEBUG=true AND USE_SQLITE=true AND we're not
# running tests. This is a deliberately strict gate — the toolbar
# exposes query internals, settings, and request state that should
# never appear in production. The USE_SQLITE half of the check acts
# as a belt-and-suspenders guard against accidentally enabling DEBUG
# on production (which would be its own serious problem, but at least
# wouldn't leak toolbar data).
#
# Test-run skip: Django forces DEBUG=False during `manage.py test`,
# which makes the toolbar emit its own E001 system-check error AND
# leaves template tags referencing the unregistered `djdt` URL
# namespace — both fatal to the test suite. Detecting the test
# command up-front and skipping the install entirely is cleaner than
# trying to work around both symptoms.
import sys as _sys
_IS_RUNNING_TESTS = 'test' in _sys.argv
if DEBUG and _IS_DEV and not _IS_RUNNING_TESTS:
try:
import debug_toolbar # noqa: F401 — probe for installed package
except ImportError:
pass
else:
INSTALLED_APPS += ['debug_toolbar']
# Insert the middleware as early as possible in the chain so it
# captures every request, but AFTER SecurityMiddleware (standard
# recommendation in the toolbar's install docs).
MIDDLEWARE.insert(1, 'debug_toolbar.middleware.DebugToolbarMiddleware')
INTERNAL_IPS = ['127.0.0.1', 'localhost']
DEBUG_TOOLBAR_CONFIG = {
# Don't auto-collapse the SQL panel — the SQL count is the
# main thing we check on every page.
'SHOW_COLLAPSED': False,
# Explicit check so the toolbar ONLY renders when the hosting
# flags are still set (guards against stale cached pages).
'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG and _IS_DEV,
}

View File

@ -11,4 +11,15 @@ urlpatterns = [
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# === DEV-ONLY: Django Debug Toolbar URL include ===
# Matches the conditional load in settings.py. No-op in prod.
if 'debug_toolbar' in settings.INSTALLED_APPS:
try:
from debug_toolbar.toolbar import debug_toolbar_urls
urlpatterns += debug_toolbar_urls()
except ImportError:
import debug_toolbar
from django.urls import include, path
urlpatterns += [path('__debug__/', include(debug_toolbar.urls))]

View File

@ -2,4 +2,5 @@ Django==5.2.7
mysqlclient==2.2.7
python-dotenv==1.1.1
pillow==12.1.1
weasyprint==68.1
weasyprint==68.1
django-debug-toolbar==6.0.0