Jak Mogę zobaczyć uruchomione surowe zapytania SQL Django?

Czy istnieje sposób, aby pokazać SQL, który Django uruchamia podczas wykonywania zapytania?

 351
Author: Nathan Wailes, 2009-07-02

16 answers

Zobacz FAQ docs: "Jak mogę zobaczyć uruchomione surowe zapytania SQL Django?"

django.db.connection.queries zawiera listę zapytań SQL:

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

Querysets mają równieżquery atrybut zawierający zapytanie do wykonania:

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

Zauważ, że wyjście zapytania nie jest poprawne SQL, ponieważ:

"Django nigdy w rzeczywistości nie interpoluje parametrów: wysyła zapytanie i parametry oddzielnie do adaptera bazy danych, który wykonuje odpowiednie operacje."

From Django bug report #17741.

Z tego powodu nie należy wysyłać zapytania bezpośrednio do bazy danych.

 427
Author: geowa4,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-30 04:32:45

Django-rozszerzenia mają polecenie shell_plus z parametrem print-sql

./manage.py shell_plus --print-sql

W django-shell wydrukowane zostaną wszystkie wykonane zapytania

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>
 76
Author: Patrick Z,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-16 09:43:29

Spójrz na debug_toolbar , jest bardzo przydatny do debugowania.

Dokumentacja i źródło są dostępne na stronie http://django-debug-toolbar.readthedocs.io/.

Zrzut ekranu paska narzędzi debugowania

 53
Author: Glader,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-14 17:38:58

Żadna inna odpowiedź nie obejmuje tej metody, więc:

Uważam, że zdecydowanie najbardziej użyteczną, prostą i niezawodną metodą jest zapytanie bazy danych. Na przykład w Linuksie dla Postgres można zrobić:

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 logach bazy danych zobaczysz nie tylko surowy SQL, ale także wszelkie ustawienia połączenia lub transakcje, które django umieszcza w systemie.

 28
Author: Bryce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-31 23:31:22

Zapytanie jest faktycznie osadzone w API modeli:

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

print(q.query)
 27
Author: jgabrielsk8,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-12 10:56:30

Chociaż możesz to zrobić za pomocą dostarczonego kodu, uważam, że korzystanie z aplikacji debug toolbar jest świetnym narzędziem do wyświetlania zapytań. Możesz go pobrać z github tutaj .

Daje to możliwość pokazania wszystkich zapytań uruchomionych na danej stronie wraz z czasem, jaki zajęło zapytanie. Podsumowuje również liczbę zapytań na stronie wraz z całkowitym czasem na szybki przegląd. Jest to świetne narzędzie, gdy chcesz zobaczyć, co Django ORM robi za kulisami. Ma również wiele inne ładne funkcje, które możesz użyć, jeśli chcesz.

 18
Author: googletorp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-02 13:47:29

Inna opcja, zobacz Opcje logowania w settings.py opisane przez ten post

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

Debug_toolbar spowalnia każde obciążenie strony na serwerze dev, logowanie NIE JEST więc szybsze. Wyjścia mogą być przesyłane do konsoli lub pliku, więc interfejs użytkownika nie jest tak miły. Ale w przypadku widoków z dużą ilością SQL debugowanie i optymalizacja SQL za pomocą debug_toolbar może zająć dużo czasu, ponieważ każde ładowanie strony jest tak powolne.

 16
Author: Overclocked,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-27 15:45:16

Jeśli upewnisz się, że Twoje settings.py plik ma:

  1. django.core.context_processors.debug wymienione w CONTEXT_PROCESSORS
  2. DEBUG=True
  3. twoje IP w INTERNAL_IPS krotce

Wtedy powinieneś mieć dostęp do zmiennej sql_queries. Dodaję stopkę do każdej strony, która wygląda tak:

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

Otrzymałem 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.

 10
Author: Mike Howsden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-16 19:01:07

W tym celu opracowałem rozszerzenie, dzięki któremu można łatwo umieścić dekorator w funkcji widoku i zobaczyć, ile zapytań jest wykonywanych.

Aby 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()

Do użycia jako dekorator:

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

 8
Author: rabbit.aaron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-16 10:36:06

Wystarczy dodać, w django, jeśli masz zapytanie takie jak:

MyModel.objects.all()

Do:

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

Lub:

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

Aby uzyskać ciąg sql

 6
Author: robert wallace,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-26 06:50:30

Uważam, że to powinno zadział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())}')
 3
Author: chander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-31 14:16:36

Umieściłem 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)))

Wtedy, gdy jest to potrzebne, po prostu importuję go i wywołuję z dowolnego kontekstu (Zwykle widoku), np.:

# ... 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

Miło jest to zrobić poza szablonem, ponieważ wtedy, jeśli masz widoki API (Zwykle Django Rest Framework), to również tam się znajduje zastosowanie.

 3
Author: getup8,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-15 00:35:02

Poniższe zapytanie zwraca 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 '):]
 2
Author: Flash,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-29 00:01:15

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)

Przyjmuje jako funkcję parametrów (zawiera zapytania sql) inspect i args, kwargs potrzebne do wywołania tej funkcji. W rezultacie zwraca to, co funkcja zwraca i wyświetla zapytania SQL w konsoli.

 2
Author: turkus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-25 10:23:56

Dla Django 2.2:

Ponieważ większość odpowiedzi nie pomogła mi zbytnio przy użyciu ./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 tylko pokazuję mi obiekt. Użycie __str__()(reprezentacja łańcuchowa) wyświetla pełne zapytanie.

 1
Author: goutham_mi3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-03 19:18:59

View Queries using django.db.połączenie.queries

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

Dostęp do surowego zapytania SQL na obiekcie QuerySet

 qs = MyModel.objects.all()
 print(qs.query)
 0
Author: Muhammad Parwej,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-01 10:28:28