Как я могу увидеть необработанные запросы SQL, которые выполняет Django?

233

Есть ли способ показать SQL, который Django запускает при выполнении запроса?

Теги:

13 ответов

270
Лучший ответ

См. Часто задаваемые вопросы по документам: " Как я могу увидеть необработанные SQL-запросы, выполняемые Django? "

django.db.connection.queries содержит список запросов SQL:

from django.db import connection
print connection.queries

Наборы запросов также имеют атрибут query содержащий запрос, который должен быть выполнен:

print MyModel.objects.filter(name="my name").query

Обратите внимание, что вывод запроса не является допустимым SQL, потому что:

"Django никогда не интерполирует параметры: он отправляет запрос и параметры отдельно адаптеру базы данных, который выполняет соответствующие операции".

Из сообщения об ошибке Django № 17741.

Из-за этого вам не следует отправлять вывод запроса непосредственно в базу данных.

  • 11
    Чтобы подтвердить этот ответ на будущее, вам следует связать текущую версию документации Django: docs.djangoproject.com/en/dev/faq/models/…
  • 19
    или просто напиши ответ! Потому что люди, подобные мне, ищут решение ...
Показать ещё 4 комментария
35

Взгляните на debug_toolbar, это очень полезно для отладки.

Документация и источник доступны по адресу http://django-debug-toolbar.readthedocs.io/.

Изображение 923

  • 1
    debug_toolbar особенно полезен, когда у вас есть запрос, который терпит неудачу с ошибкой синтаксиса SQL; он будет отображать последний запрос, который был выполнен (и не выполнен), что облегчает его отладку.
29

Django-extensions имеют команду shell_plus с параметром print-sql

./manage.py shell_plus --print-sql

В django-shell все выполненные запросы будут напечатаны

Пример:.

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>
  • 0
    Я использую его с --print-sql или с SHELL_PLUS_PRINT_SQL = True, и это не помогает - я все еще не вижу запросы. есть идеи почему? Джанго 1,8
16
q = Query.objects.values('val1','val2','val_etc')

print q.query
  • 2
    или str(q.query)
16

Хотя вы можете сделать это с помощью прилагаемого кода, я считаю, что использование приложения панели инструментов отладки - отличный инструмент для показа запросов. Вы можете скачать его из github здесь.

Это дает вам возможность показывать все запросы, запущенные на заданной странице, и время, затраченное на запрос. Он также суммирует количество запросов на странице вместе с общим временем для быстрого обзора. Это отличный инструмент, когда вы хотите посмотреть, что делает Django ORM за кулисами. В нем также есть много других приятных функций, которые вы можете использовать, если хотите.

15

Никакой другой ответ не охватывает этот метод, поэтому:

Я нахожу, что наиболее полезным, простым и надежным методом является запрос вашей базы данных. Например, в Linux для Postgres вы можете:

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

Каждая база данных будет иметь несколько другую процедуру. В журналах базы данных вы увидите не только необработанный SQL, но и любую установку соединения или транзакционную служебную запись django, размещенную в системе.

  • 5
    не забудьте установить log_statement='all' в postgresql.conf для этого метода.
10

Еще одна опция, см. параметры ведения журнала в settings.py, описанные в этом сообщении

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

debug_toolbar замедляет загрузку каждой страницы на вашем сервере dev, ведение журнала не так быстро. Выходы могут быть сброшены в консоль или файл, поэтому пользовательский интерфейс не такой приятный. Но для представлений с большим количеством SQL-запросов может потребоваться много времени, чтобы отлаживать и оптимизировать SQL-запросы через debug_toolbar, поскольку каждая загрузка на странице настолько медленная.

  • 0
    Отлично! Хотя панель инструментов выглядит великолепно, я думаю, что этот ответ должен быть принятым. Это решение, которое я хотел, потому что оно позволяет «manage.py runserver» регистрировать SQL на консоли и работает с «manage.py migrate». Последнее позволило мне увидеть, что «при удалении каскад» определенно не был установлен при создании моих таблиц. Стоит отметить, что этот ответ основан на docs.djangoproject.com/en/1.9/topics/logging/…
10

Если вы убедитесь, что у вашего файла settings.py есть:

  • django.core.context_processors.debug, перечисленные в CONTEXT_PROCESSORS
  • DEBUG=True
  • ваш IP в кортеже INTERNAL_IPS

Затем вы должны иметь доступ к переменной sql_queries. Я добавляю нижний колонтитул на каждую страницу, которая выглядит так:

{%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 %}

Я получил переменную sql_time_sum, добавив строку

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

для функции отладки в django_src/django/core/context_processors.py.

  • 0
    Я только что попробовал это, и (удалив часть sql_time_sum), получил: Нет именованных циклов в шаблоне. «нечетное, четное» не определено - что мне не хватает?
2

Я разработал расширение для этой цели, чтобы вы могли легко разместить декоратор в своей функции просмотра и посмотреть, сколько запросов выполнено.

Установить:

$ pip install django-print-sql

Для использования в качестве менеджера контекста:

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 performance

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

Для использования в качестве декоратора:

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

1

Я считаю, что это должно работать, если вы используете 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())}')
  • 0
    Это работало даже в Python 2. Только рефакторинг, такой как print (cursor.mogrify (* qs.query.sql_with_params ())) - все, что ему нужно.
  • 0
    IIRC Cursor.mogrify возвращает строку, поэтому я предполагаю, что использование строки f для форматирования является излишним.
1

Далее возвращается запрос как действительный SQL на основе 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 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 '):]
0

Я смог увидеть неудачные запросы, просто выполнив:

tail -f /var/log/postgresql/*

Предполагалось, что postgres 10.6, ubuntu 18. 04+, python3+, django2+ и что регистрация включена в postgres.

0

Я сделал небольшой фрагмент, который вы можете использовать:

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)

Он принимает в качестве параметров функцию (содержит SQL-запросы) для проверки и аргументов, kwargs, необходимых для вызова этой функции. В результате он возвращает то, что возвращает функция, и печатает SQL-запросы в консоли.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню