[sql] How can I see the raw SQL queries Django is running?

Is there a way to show the SQL that Django is running while performing a query?

This question is related to sql django

The answer is


Another option, see logging options in settings.py described by this post

http://dabapps.com/blog/logging-sql-queries-django-13/

debug_toolbar slows down each page load on your dev server, logging does not so it's faster. Outputs can be dumped to console or file, so the UI is not as nice. But for views with lots of SQLs, it can take a long time to debug and optimize the SQLs through debug_toolbar since each page load is so slow.


I developed an extension for this purpose, so you can easily put a decorator on your view function and see how many queries are executed.

To install:

$ pip install django-print-sql

To use as context manager:

from django_print_sql import print_sql

# set `count_only` to `True` will print the number of executed SQL statements only
with print_sql(count_only=False):

  # write the code you want to analyze in here,
  # e.g. some complex foreign key lookup,
  # or analyzing a DRF serializer's performance

  for user in User.objects.all()[:10]:
      user.groups.first()

To use as decorator:

from django_print_sql import print_sql_decorator


@print_sql_decorator(count_only=False)  # this works on class-based views as well
def get(request):
    # your view code here

Github: https://github.com/rabbit-aaron/django-print-sql


I've made a small snippet you can use:

from django.conf import settings
from django.db import connection


def sql_echo(method, *args, **kwargs):
    settings.DEBUG = True
    result = method(*args, **kwargs)
    for query in connection.queries:
        print(query)
    return result


# HOW TO USE EXAMPLE:
# 
# result = sql_echo(my_method, 'whatever', show=True)

It takes as parameters function (contains sql queryies) to inspect and args, kwargs needed to call that function. As the result it returns what function returns and prints SQL queries in a console.


If you make sure your settings.py file has:

  1. django.core.context_processors.debug listed in CONTEXT_PROCESSORS
  2. DEBUG=True
  3. your IP in the INTERNAL_IPS tuple

Then you should have access to the sql_queries variable. I append a footer to each page that looks like this:

{%if sql_queries %}
  <div class="footNav">
    <h2>Queries</h2>
    <p>
      {{ sql_queries|length }} Quer{{ sql_queries|pluralize:"y,ies" }}, {{sql_time_sum}} Time
    {% ifnotequal sql_queries|length 0 %}
      (<span style="cursor: pointer;" onclick="var s=document.getElementById('debugQueryTable').style;s.disp\
lay=s.display=='none'?'':'none';this.innerHTML=this.innerHTML=='Show'?'Hide':'Show';">Show</span>)
    {% endifnotequal %}
    </p>
    <table id="debugQueryTable" style="display: none;">
      <col width="1"></col>
      <col></col>
      <col width="1"></col>
      <thead>
        <tr>
          <th scope="col">#</th>
          <th scope="col">SQL</th>
          <th scope="col">Time</th>
        </tr>
      </thead>
      <tbody>
        {% for query in sql_queries %}
          <tr class="{% cycle odd,even %}">
            <td>{{ forloop.counter }}</td>
            <td>{{ query.sql|escape }}</td>
            <td>{{ query.time }}</td>
          </tr>
        {% endfor %}
      </tbody>
    </table>
  </div>
{% endif %}

I got the variable sql_time_sum by adding the line

context_extras['sql_time_sum'] = sum([float(q['time']) for q in connection.queries])

to the debug function in django_src/django/core/context_processors.py.


I believe this ought to work if you are using PostgreSQL:

from django.db import connections
from app_name import models
from django.utils import timezone

# Generate a queryset, use your favorite filter, QS objects, and whatnot.
qs=models.ThisDataModel.objects.filter(user='bob',date__lte=timezone.now())

# Get a cursor tied to the default database
cursor=connections['default'].cursor()

# Get the query SQL and parameters to be passed into psycopg2, then pass
# those into mogrify to get the query that would have been sent to the backend
# and print it out. Note F-strings require python 3.6 or later.
print(f'{cursor.mogrify(*qs.query.sql_with_params())}')

Django-extensions have a command shell_plus with a parameter print-sql

./manage.py shell_plus --print-sql

In django-shell all executed queries will be printed

Ex.:

User.objects.get(pk=1)
SELECT "auth_user"."id",
       "auth_user"."password",
       "auth_user"."last_login",
       "auth_user"."is_superuser",
       "auth_user"."username",
       "auth_user"."first_name",
       "auth_user"."last_name",
       "auth_user"."email",
       "auth_user"."is_staff",
       "auth_user"."is_active",
       "auth_user"."date_joined"
FROM "auth_user"
WHERE "auth_user"."id" = 1

Execution time: 0.002466s [Database: default]

<User: username>

For Django 2.2:

As most of the answers did not helped me much when using ./manage.py shell. Finally i found the answer. Hope this helps to someone.

To view all the queries:

from django.db import connection
connection.queries

To view query for a single query:

q=Query.objects.all()
q.query.__str__()

q.query just displaying the object for me. Using the __str__()(String representation) displayed the full query.


No other answer covers this method, so:

I find by far the most useful, simple, and reliable method is to ask your database. For example on Linux for Postgres you might do:

sudo su postgres
tail -f /var/log/postgresql/postgresql-8.4-main.log

Each database will have slightly different procedure. In the database logs you'll see not only the raw SQL, but any connection setup or transaction overhead django is placing on the system.


Take a look at debug_toolbar, it's very useful for debugging.

Documentation and source is available at http://django-debug-toolbar.readthedocs.io/.

Screenshot of debug toolbar


The following returns the query as valid SQL, based on https://code.djangoproject.com/ticket/17741:

def str_query(qs):
    """
    qs.query returns something that isn't valid SQL, this returns the actual
    valid SQL that's executed: https://code.djangoproject.com/ticket/17741
    """
    cursor = connections[qs.db].cursor()
    query, params = qs.query.sql_with_params()
    cursor.execute('EXPLAIN ' + query, params)
    res = str(cursor.db.ops.last_executed_query(cursor, query, params))
    assert res.startswith('EXPLAIN ')
    return res[len('EXPLAIN '):]

The query is actually embedded in the models API:

q = Query.objects.values('val1','val2','val_etc')

print(q.query)

To get result query from django to database(with correct parameter substitution) you could use this function:

from django.db import connection

def print_database_query_formatted(query):
    sql, params = query.sql_with_params()
    cursor = connection.cursor()
    cursor.execute('EXPLAIN ' + sql, params)
    db_query = cursor.db.ops.last_executed_query(cursor, sql, params).replace('EXPLAIN ', '')

    parts = '{}'.format(db_query).split('FROM')
    print(parts[0])
    if len(parts) > 1:
        parts = parts[1].split('WHERE')
        print('FROM{}'.format(parts[0]))
        if len(parts) > 1:
            parts = parts[1].split('ORDER BY')
            print('WHERE{}'.format(parts[0]))
            if len(parts) > 1:
                print('ORDER BY{}'.format(parts[1]))

# USAGE
users = User.objects.filter(email='[email protected]').order_by('-id')
print_database_query_formatted(users.query)

Output example

SELECT "users_user"."password", "users_user"."last_login", "users_user"."is_superuser", "users_user"."deleted", "users_user"."id", "users_user"."phone", "users_user"."username", "users_user"."userlastname", "users_user"."email", "users_user"."is_staff", "users_user"."is_active", "users_user"."date_joined", "users_user"."latitude", "users_user"."longitude", "users_user"."point"::bytea, "users_user"."default_search_radius", "users_user"."notifications", "users_user"."admin_theme", "users_user"."address", "users_user"."is_notify_when_buildings_in_radius", "users_user"."active_campaign_id", "users_user"."is_unsubscribed", "users_user"."sf_contact_id", "users_user"."is_agree_terms_of_service", "users_user"."is_facebook_signup", "users_user"."type_signup" 
FROM "users_user" 
WHERE "users_user"."email" = '[email protected]' 
ORDER BY "users_user"."id" DESC

It based on this ticket comment: https://code.djangoproject.com/ticket/17741#comment:4


View Queries using django.db.connection.queries

from django.db import connection
print(connection.queries)

Access raw SQL query on QuerySet object

 qs = MyModel.objects.all()
 print(qs.query)

I put this function in a util file in one of the apps in my project:

import logging
import re

from django.db import connection

logger = logging.getLogger(__name__)

def sql_logger():
    logger.debug('TOTAL QUERIES: ' + str(len(connection.queries)))
    logger.debug('TOTAL TIME: ' + str(sum([float(q['time']) for q in connection.queries])))

    logger.debug('INDIVIDUAL QUERIES:')
    for i, query in enumerate(connection.queries):
        sql = re.split(r'(SELECT|FROM|WHERE|GROUP BY|ORDER BY|INNER JOIN|LIMIT)', query['sql'])
        if not sql[0]: sql = sql[1:]
        sql = [(' ' if i % 2 else '') + x for i, x in enumerate(sql)]
        logger.debug('\n### {} ({} seconds)\n\n{};\n'.format(i, query['time'], '\n'.join(sql)))

Then, when needed, I just import it and call it from whatever context (usually a view) is necessary, e.g.:

# ... other imports
from .utils import sql_logger

class IngredientListApiView(generics.ListAPIView):
    # ... class variables and such

    # Main function that gets called when view is accessed
    def list(self, request, *args, **kwargs):
        response = super(IngredientListApiView, self).list(request, *args, **kwargs)

        # Call our function
        sql_logger()

        return response

It's nice to do this outside the template because then if you have API views (usually Django Rest Framework), it's applicable there too.


Though you can do it with with the code supplied, I find that using the debug toolbar app is a great tool to show queries. You can download it from github here.

This gives you the option to show all the queries ran on a given page along with the time to query took. It also sums up the number of queries on a page along with total time for a quick review. This is a great tool, when you want to look at what the Django ORM does behind the scenes. It also have a lot of other nice features, that you can use if you like.


Just to add, in django, if you have a query like:

MyModel.objects.all()

do:

MyModel.objects.all().query.sql_with_params()

or:

str(MyModel.objects.all().query)

to get the sql string