Есть ли способ показать SQL, который Django запускает при выполнении запроса?
Как я могу просмотреть необработанные SQL-запросы Django?
Ответ 1
См. часто задаваемые вопросы по документам: "Как узнать, какие необработанные запросы 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.
Из-за этого вы не должны отправлять вывод запроса непосредственно в базу данных.
Ответ 2
Взгляните на debug_toolbar, это очень полезно для отладки.
Документация и источник доступны по адресу http://django-debug-toolbar.readthedocs.io/.
Ответ 3
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>
Ответ 4
Никакой другой ответ не охватывает этот метод, поэтому:
Я нахожу, что наиболее полезным, простым и надежным методом является запрос вашей базы данных. Например, в Linux для Postgres вы можете:
sudo su postgres
tail -f /var/log/postgresql/postgresql-8.4-main.log
Каждая база данных будет иметь несколько другую процедуру. В журналах базы данных вы увидите не только необработанный SQL, но и любую установку соединения или транзакционную служебную запись django, размещенную в системе.
Ответ 5
q = Query.objects.values('val1','val2','val_etc')
print q.query
Ответ 6
Хотя вы можете сделать это с помощью прилагаемого кода, я считаю, что использование приложения панели инструментов отладки - отличный инструмент для показа запросов. Вы можете скачать его из github здесь.
Это дает вам возможность показывать все запросы, запущенные на заданной странице, и время, затраченное на запрос. Он также суммирует количество запросов на странице вместе с общим временем для быстрого обзора. Это отличный инструмент, когда вы хотите посмотреть, что делает Django ORM за кулисами. В нем также есть много других приятных функций, которые вы можете использовать, если хотите.
Ответ 7
Еще одна опция, см. параметры ведения журнала в settings.py, описанные в этом сообщении
http://dabapps.com/blog/logging-sql-queries-django-13/
debug_toolbar замедляет загрузку каждой страницы на вашем сервере dev, ведение журнала не так быстро. Выходы могут быть сброшены в консоль или файл, поэтому пользовательский интерфейс не такой приятный. Но для представлений с большим количеством SQL-запросов может потребоваться много времени, чтобы отлаживать и оптимизировать SQL-запросы через debug_toolbar, поскольку каждая загрузка на странице настолько медленная.
Ответ 8
Если вы убедитесь, что у вашего файла 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.
Ответ 9
Я разработал расширение для этой цели, чтобы вы могли легко разместить декоратор в вашей функции просмотра и посмотреть, сколько запросов выполнено.
Установить:
$ 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
Ответ 10
Я сделал небольшой фрагмент, который вы можете использовать:
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-запросы в консоли.
Ответ 11
Далее возвращается запрос как действительный 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 '):]
Ответ 12
Я считаю, что это должно работать, если вы используете 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())}')
Ответ 13
Я поместил эту функцию в файл утилит в одном из приложений в моем проекте:
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)))
Затем, когда это необходимо, я просто импортирую его и вызываю из любого необходимого контекста (обычно представления), например:
# ... 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
Приятно делать это вне шаблона, потому что тогда, если у вас есть представления API (обычно Django Rest Framework), они применимы и там.
Ответ 14
Я смог увидеть неудачные запросы, просто выполнив:
tail -f /var/log/postgresql/*
Предполагалось, что postgres 10.6, ubuntu 18. 04+, python3+, django2+ и что регистрация включена в postgres.