Getting the SQL from a Django QuerySet
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Django's ORM generates SQL behind the scenes when you use QuerySets. Viewing the actual SQL is essential for debugging slow queries, understanding ORM behavior, verifying complex filters, and optimizing database performance. Django provides several ways to inspect the generated SQL — from the .query attribute to the Django Debug Toolbar.
Method 1: str(queryset.query)
The simplest way — access the .query attribute on any QuerySet:
Note: .query does not include parameter quoting — values appear inline without proper escaping. This SQL is for inspection only, not for direct execution.
Method 2: queryset.query.sql_with_params()
Get the SQL with parameterized placeholders:
This is closer to what Django actually sends to the database.
Method 3: django.db.connection.queries
Django logs all executed queries when DEBUG=True:
This only works when settings.DEBUG = True. In production, queries are not logged.
Method 4: EXPLAIN / EXPLAIN ANALYZE
Get the database's query execution plan:
EXPLAIN shows how the database plans to execute the query without running it. EXPLAIN ANALYZE runs the query and shows actual execution statistics.
Method 5: Django Debug Toolbar
The Django Debug Toolbar provides a visual SQL panel showing all queries per request:
The SQL panel shows each query, its execution time, duplicate queries, and the traceback showing where in your code each query was triggered.
Method 6: Logging SQL Queries
Configure Django's logging to print all SQL to the console:
Every SQL query will now appear in the console output during development.
Complex QuerySet Examples
Aggregation
Subqueries
JOINs with select_related
Counting Queries in Tests
Common Pitfalls
.queryshows unquoted parameters: The SQL fromstr(qs.query)does not properly escape string values. Do not copy-paste it into a database client — it may have syntax errors. Usesql_with_params()for parameterized SQL.- N+1 query problem: Accessing related objects in a loop generates one query per object. Use
select_related()(foreign keys) andprefetch_related()(reverse/many-to-many) to join them in a single query. connection.queriesonly works with DEBUG=True: In production (DEBUG=False), the query log is disabled for performance. Use thedjango.db.backendslogger or a monitoring tool like Sentry for production SQL inspection..queryon evaluated QuerySets:.queryis available even after the QuerySet is evaluated. It shows the SQL that was (or would be) executed, which is useful for debugging after the fact.- Raw SQL vs ORM: If
.queryshows unexpected SQL, check your filters and annotations. The ORM sometimes generates suboptimal queries — use.raw()orconnection.cursor()for hand-tuned SQL when performance is critical.
Summary
- Use
str(qs.query)for quick SQL inspection during development - Use
qs.query.sql_with_params()for parameterized SQL with proper placeholders - Use
connection.queriesto see all executed queries (requiresDEBUG=True) - Use
qs.explain(analyze=True)to get the database execution plan - Use Django Debug Toolbar for visual query analysis per request
- Configure
django.db.backendslogger for automatic SQL logging to console
Related reading
- Getting timestamp from mongodb id
- Git Push Error insufficient permission for adding an object to repository database
- Git Push Error insufficient permission for adding an object to repository database
- Given an RGB value what would be the best way to find the closest match in the database?
- Getting today's date in YYYY-MM-DD in Python?
- Getting today's date in YYYY-MM-DD in Python?
- Global setting for AsNoTracking?
- GO statements blowing up sql execution in .NET

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.