django-query-doctor
Diagnose and fix slow Django ORM queries. Detects N+1s, duplicates, missing indexes, and more — with exact file:line references and actionable fixes.
The Problem
Every Django app accumulates hidden query inefficiencies — N+1 loops behind serializers, duplicate fetches scattered across views, full table scans on unindexed columns. django-query-doctor intercepts queries at runtime using connection.execute_wrapper(), runs them through 8 analyzers, and produces prescriptions with the exact file, line, and code fix. It works in middleware, tests, CI pipelines, and management commands — no DEBUG=True required.
Install
pip install django-query-doctor
# settings.py
INSTALLED_APPS = [..., "query_doctor"]
MIDDLEWARE = [..., "query_doctor.middleware.QueryDoctorMiddleware"]
See It in Action
from query_doctor.context_managers import diagnose_queries
with diagnose_queries() as report:
books = list(Book.objects.all())
for book in books:
_ = book.author.name # triggers N+1
assert report.issues > 0
print(f"Found {report.issues} issues in {report.total_queries} queries")
Console output (plain-text renderer; Rich adds colors and panels):
============================================================
Query Doctor Report
Total queries: 13 | Time: 0.2ms | Issues: 2
============================================================
CRITICAL: N+1 detected: 12 queries for table "myapp_author" (field: author)
Location: myapp/views.py:12 in list_books
Code: _ = book.author.name # triggers N+1
Fix: Add .select_related('author') to your queryset
Queries: 12 | Est. savings: ~0.2ms
INFO: Fat SELECT: 8 columns from "myapp_book" including large fields: description
Location: myapp/views.py:10 in list_books
Code: books = list(Book.objects.all())
Fix: Use .defer('description') to skip loading large fields, or .values()/.values_list() if you don't need model instances
Queries: 1 | Est. savings: ~0.0ms
What It Detects
| Issue | What It Catches |
|---|---|
| N+1 Queries | Related objects loaded one-per-row in loops |
| Duplicate Queries | Same SQL executed multiple times per request |
| Missing Indexes | Filters on columns without database indexes |
| Fat SELECT | Fetching all columns when only a few are used |
| QuerySet Evaluation | len(qs) instead of qs.count(), bool(qs) instead of qs.exists() |
| Query Complexity | Excessive JOINs, subqueries, or OR chains |
| SerializerMethodField | AST analysis of get_<field> method bodies for hidden N+1s |
Every prescription includes: severity, file:line, and the exact code fix.
QueryTurbo (v2.0)
QueryTurbo reduces SQL compilation overhead by caching compiled query structures and extracting parameters directly from Django's Query tree, bypassing repeated calls to SQLCompiler.as_sql(). Queries are validated across 3 executions before the compilation step is skipped entirely. Enable it in settings:
QUERY_DOCTOR = {
"TURBO": {"ENABLED": True}
}
Requirements
- Python 3.10+
- Django 4.2, 5.0, 5.1, 5.2, or 6.0
- Optional extras:
pip install django-query-doctor[rich]for styled console output,[celery]for Celery task support,[otel]for OpenTelemetry export - Optional third-party packages (install separately, not query-doctor extras): DRF for serializer analysis, psycopg3 for prepared-statement support
Links
📖 Documentation | 📦 PyPI | 📝 Changelog | 🐛 Issues
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_query_doctor-2.2.0.tar.gz.
File metadata
- Download URL: django_query_doctor-2.2.0.tar.gz
- Upload date:
- Size: 362.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ea022beba34c5baa2155bf69d702acab0ae8127d42b52ee5d06a96c64966ef7
|
|
| MD5 |
244b6404548c689f92c2db676e0d80a6
|
|
| BLAKE2b-256 |
efec5fd21b69c09c08265550fc2a695e57d8c79be0e04c9bd87bc1632c533328
|
File details
Details for the file django_query_doctor-2.2.0-py3-none-any.whl.
File metadata
- Download URL: django_query_doctor-2.2.0-py3-none-any.whl
- Upload date:
- Size: 131.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8373dcd176ef53737a55ccac9fb04ff9db75c0d2e93203b582bd27817e4417a7
|
|
| MD5 |
6c1f0c55cf8b75c899d467668985c2bf
|
|
| BLAKE2b-256 |
aa065320e4ea2083dd0616fe9c20138a6b1616ec0bf0ca9c9ffc934fd3e0f714
|