How can I see the raw SQL queries Django is running?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Django’s ORM builds SQL for you, but when performance or correctness matters, you often need to see the actual query sent to the database. The right tool depends on whether you want the SQL for one queryset, all queries in a request, or long-term logging across an environment.
Inspect a Single QuerySet
If you already have a queryset, the quickest way to inspect its SQL is the queryset’s query object:
This prints the SQL Django would generate for that queryset. It is useful when you are debugging filters, joins, ordering, or slicing.
A detail worth remembering is that a queryset is lazy. The SQL string can be inspected before execution, but the database call does not happen until the queryset is evaluated.
Capture Executed Queries During a Request
If you want the queries Django actually executed, use connection.queries in a debug environment:
This is helpful when one page or one view fires many ORM calls and you want to spot repeated queries or N+1 problems.
However, connection.queries is primarily a development tool. It is only populated when DEBUG is enabled, and it adds overhead, so it is not something to leave on casually in production.
Use Django Logging for Ongoing Visibility
For broader visibility, configure SQL logging through Django’s logging settings:
With that in place, executed SQL statements are written to the console. This is often the easiest way to watch ORM activity while exercising the application manually.
It is also more practical than sprinkling print(connection.queries) throughout the codebase.
Use QuerySet.explain() for Performance Investigation
Sometimes seeing raw SQL is not enough. You also want to know how the database plans to execute it. Django provides explain() for supported backends:
This does not replace reading raw SQL, but it is the next step when the query is correct and still too slow.
Django Debug Toolbar Is Often the Best Development Experience
For web request debugging, Django Debug Toolbar is often the most convenient option. It shows each query, execution time, duplicate patterns, and stack context inside the browser.
That makes it much easier to answer questions such as:
- which view triggered this query
- how many queries did the page run
- which query is slow
- where is the N+1 relationship problem coming from
For one-off command-line debugging, print(qs.query) is fine. For interactive view debugging, the toolbar is usually faster.
Common Pitfalls
The biggest mistake is assuming print(qs.query) shows every query the request executed. It only shows one queryset’s SQL, not the full request behavior.
Another issue is using connection.queries without realizing it depends on debug behavior and can distort performance observations by adding overhead.
Developers also sometimes compare the printed SQL too literally across database backends. Django may parameterize or format queries differently depending on the driver and engine.
Finally, do not leave verbose SQL logging enabled in production unless you have a deliberate operational reason. It can create noise, overhead, and security concerns around logged query text.
Summary
- Use
print(qs.query)to inspect the SQL for one queryset. - Use
connection.queriesto inspect executed queries in a debug environment. - Configure
django.db.backendslogging for ongoing SQL visibility. - Use
explain()when the query is correct but performance is unclear. - Prefer development tools such as Django Debug Toolbar for request-level analysis.

