Odpowiedzi:
Zobacz często zadawane pytania dotyczące dokumentacji: „ Jak mogę zobaczyć surowe zapytania SQL, które uruchamia Django? ”
django.db.connection.queries
zawiera listę zapytań SQL:
from django.db import connection
print(connection.queries)
Zestawy zapytań mają również query
atrybut zawierający zapytanie do wykonania:
print(MyModel.objects.filter(name="my name").query)
Zauważ, że wynik zapytania nie jest prawidłowym SQL, ponieważ:
„Django nigdy nie interpoluje parametrów: wysyła zapytanie i parametry osobno do adaptera bazy danych, który wykonuje odpowiednie operacje.”
Z raportu o błędzie Django # 17741 .
Z tego powodu nie należy wysyłać wyników zapytania bezpośrednio do bazy danych.
str()
funkcji języka Python , która wywołuje __str__()
metodę wewnętrzną . np. str(MyModel.objects.filter(name="my name").query)
Poleciłbym również użycie IPython i powłoki Django twojego projektu. Uzupełnianie tabulatorów zapewnia introspekcję obiektu. Ponieważ Django znany jest z asertywnych schematów nazewnictwa, ta metodologia jest zwykle bardzo przydatna.
query
nie jest poprawnym SQL, ponieważ „Django nigdy nie interpoluje parametrów: wysyła zapytanie i parametry osobno do adaptera bazy danych, który wykonuje odpowiednie operacje”. Źródło: code.djangoproject.com/ticket/17741
stable
, a nie dev
, żeby dodać odnośnik do bieżącej wersji Django tak: docs.djangoproject.com/en/stable/faq/models/...
Rozszerzenia Django mają polecenie shell_plus z parametremprint-sql
./manage.py shell_plus --print-sql
W powłoce django zostaną wydrukowane wszystkie wykonane zapytania
Dawny.:
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>
Spójrz na debug_toolbar , jest to bardzo przydatne do debugowania.
Dokumentacja i źródło są dostępne na stronie http://django-debug-toolbar.readthedocs.io/ .
q = Query.objects.values('val1','val2','val_etc')
print q.query
m = MyModel.objects.get(...)
następujem.query
m
nie jest już zestawem zapytań. Zastosowanie q = MyModel.objects.filter(...)
, a następnie q.query
, po czym m = q.get()
.
Żadna inna odpowiedź nie obejmuje tej metody, więc:
Uważam, że najbardziej użyteczną, prostą i niezawodną metodą jest zapytanie bazy danych. Na przykład w systemie Linux dla Postgres możesz:
sudo su postgres
tail -f /var/log/postgresql/postgresql-8.4-main.log
Każda baza danych będzie miała nieco inną procedurę. W dziennikach bazy danych zobaczysz nie tylko nieprzetworzony kod SQL, ale także wszelkie ustawienia połączenia lub transakcji narzucone przez django w systemie.
log_statement='all'
się postgresql.conf
na tej metodzie.
postgresql.conf
, biegającpsql -U postgres -c 'SHOW config_file'
Chociaż możesz to zrobić za pomocą dostarczonego kodu, uważam, że korzystanie z aplikacji paska narzędzi debugowania jest doskonałym narzędziem do wyświetlania zapytań. Możesz pobrać go z github tutaj .
Daje to opcję pokazania wszystkich zapytań uruchomionych na danej stronie wraz z czasem potrzebnym na zapytanie. Podsumowuje także liczbę zapytań na stronie oraz całkowity czas na szybką recenzję. To świetne narzędzie, gdy chcesz zobaczyć, co robi Django ORM za kulisami. Ma również wiele innych fajnych funkcji, z których możesz skorzystać, jeśli chcesz.
Inna opcja, patrz opcje rejestrowania w pliku settings.py opisane w tym poście
http://dabapps.com/blog/logging-sql-queries-django-13/
debug_toolbar spowalnia każde ładowanie strony na serwerze deweloperskim, logowanie nie jest tak szybsze. Dane wyjściowe można zrzucić do konsoli lub pliku, więc interfejs użytkownika nie jest tak przyjemny. Ale w przypadku widoków z dużą ilością SQL-ów debugowanie i optymalizacja SQLów przez debug_toolbar może zająć dużo czasu, ponieważ ładowanie każdej strony jest tak wolne.
Jeśli upewnisz się, że plik settings.py ma:
django.core.context_processors.debug
wymienione w CONTEXT_PROCESSORS
DEBUG=True
IP
w INTERNAL_IPS
krotcePowinieneś mieć dostęp do sql_queries
zmiennej. Do każdej strony, która wygląda tak, dołączam stopkę:
{%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 %}
Mam zmienną sql_time_sum
, dodając linię
context_extras['sql_time_sum'] = sum([float(q['time']) for q in connection.queries])
do funkcji debugowania w django_src / django / core / context_processors.py.
W tym celu opracowałem rozszerzenie, dzięki czemu można łatwo umieścić dekorator w funkcji widoku i zobaczyć, ile zapytań jest wykonywanych.
Żeby zainstalować:
$ pip install django-print-sql
Aby użyć jako menedżera kontekstu:
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()
Aby użyć jako dekoratora:
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
Uważam, że powinno to działać, jeśli używasz 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())}')
Poniższe zwraca zapytanie jako poprawny SQL na podstawie 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 '):]
Zrobiłem mały fragment, którego możesz użyć:
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)
Jako parametr przyjmuje (funkcja kwerend SQL) kontrolę i argumenty, kwargs potrzebne do wywołania tej funkcji. W rezultacie zwraca, która funkcja zwraca, i drukuje zapytania SQL w konsoli.
Umieszczam tę funkcję w pliku util w jednej z aplikacji w moim projekcie:
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)))
Następnie, w razie potrzeby, po prostu importuję go i wywołuję z dowolnego kontekstu (zwykle widok), na przykład:
# ... 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
Fajnie jest robić to poza szablonem, ponieważ wtedy, jeśli masz widoki API (zwykle Django Rest Framework), ma to również zastosowanie.
W przypadku Django 2.2:
Ponieważ większość odpowiedzi niewiele mi pomogła podczas korzystania ./manage.py shell
. W końcu znalazłem odpowiedź. Mam nadzieję, że to komuś pomoże.
Aby wyświetlić wszystkie zapytania:
from django.db import connection
connection.queries
Aby wyświetlić zapytanie dla pojedynczego zapytania:
q=Query.objects.all()
q.query.__str__()
q.query
po prostu wyświetlam obiekt dla mnie. Za pomocą __str__()
(reprezentacja ciągu) wyświetlono pełne zapytanie.
Przeglądaj zapytania za pomocą django.db.connection.queries
from django.db import connection
print(connection.queries)
Uzyskaj dostęp do surowego zapytania SQL na obiekcie QuerySet
qs = MyModel.objects.all()
print(qs.query)
Wystarczy dodać w django, jeśli masz zapytanie takie jak:
MyModel.objects.all()
zrobić:
MyModel.objects.all().query.sql_with_params()
aby uzyskać ciąg SQL