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
Metadata
Release files for django-query-doctor 2.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_query_doctor-2.3.0.tar.gz | 400.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_query_doctor-2.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 539.5 kB
Release files / django_query_doctor-2.3.0.tar.gz
| Download URL | django_query_doctor-2.3.0.tar.gz |
|---|---|
| Size | 400.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a30ed539691f9543a38501a1a23b52219f70a120cba7a81268c6377f137b07c0
|
|
BLAKE2b-256 checksum How to use checksums |
7fc8d16059c42331c637e906d5a12549bd25f8bf00670530b8238976df4f0b34
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.0
|
Release files / django_query_doctor-2.3.0-py3-none-any.whl
| Download URL | django_query_doctor-2.3.0-py3-none-any.whl |
|---|---|
| Size | 139.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
29a768c0121f6f28ad95c7f28b3b64030262a7346dc828dbb3b6ae021259da13
|
|
BLAKE2b-256 checksum How to use checksums |
3d14ead4d55af0edb5757306236fd35dd6b201fe2d2cc0d810a808ce24006462
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.0
|