466 Stimmen

Wie kann ich die rohen SQL-Abfragen sehen, die Django ausführt?

Gibt es eine Möglichkeit, die SQL, die Django ausgeführt wird, während der Durchführung einer Abfrage zu zeigen?

11voto

Mike Howsden Punkte 415

Wenn Sie sicherstellen, dass Ihre Datei settings.py:

  1. django.core.context_processors.debug aufgeführt in CONTEXT_PROCESSORS
  2. DEBUG=True
  3. Ihr IP im INTERNAL_IPS Tupel

Dann sollten Sie Zugriff auf die sql_queries variabel. Ich füge an jede Seite eine Fußzeile an, die wie folgt aussieht:

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

Ich habe die Variable sql_time_sum durch Hinzufügen der Zeile

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

zur Debug-Funktion in django_src/django/core/context_processors.py.

9voto

mgphys Punkte 181

Django SQL Sniffer ist eine weitere Alternative, um rohe ausgeführte Abfragen aus jedem Prozess, der Django ORM nutzt, zu betrachten (und die Statistiken zu sehen). Ich habe es gebaut, um einen bestimmten Anwendungsfall zu befriedigen, die ich hatte, die ich nicht gesehen habe irgendwo abgedeckt, nämlich:

  • keine Änderungen am Quellcode, den der Zielprozess ausführt (keine Notwendigkeit, eine neue Anwendung in den Django-Einstellungen zu registrieren, Dekoratoren überall zu importieren usw.)
  • keine Änderungen an der Protokollierungskonfiguration (z. B. weil ich an einem bestimmten Prozess interessiert bin und nicht an der gesamten Prozessflotte, für die die Konfiguration gilt)
  • kein Neustart des Zielprozesses erforderlich (z. B. weil es sich um eine wichtige Komponente handelt und ein Neustart zu einer gewissen Ausfallzeit führen kann)

Daher kann Django SQL Sniffer ad-hoc verwendet und an einen bereits laufenden Prozess angehängt werden. Das Tool "schnüffelt" dann in den ausgeführten Abfragen und gibt sie auf der Konsole aus, während sie ausgeführt werden. Wenn das Tool gestoppt wird, wird eine statistische Zusammenfassung mit Ausreißer-Abfragen auf der Grundlage einer möglichen Metrik (Anzahl, maximale Dauer und kombinierte Gesamtdauer) angezeigt.

Hier ist ein Screenshot eines Beispiels, bei dem ich eine Python-Shell angehängt habe enter image description here

Sie können die Live-Demo und weitere Details auf der Github-Seite .

4voto

getup8 Punkte 5082

Ich habe diese Funktion in eine util-Datei in einer der Anwendungen in meinem Projekt eingefügt:

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

Bei Bedarf importiere ich sie dann einfach und rufe sie aus einem beliebigen Kontext (in der Regel einer Ansicht) auf, z. B.:

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

Es ist schön, dies außerhalb der Vorlage zu tun, weil dann, wenn Sie API-Ansichten (in der Regel Django Rest Framework) haben, ist es auch dort anwendbar.

4voto

Flash Punkte 14645

Im Folgenden wird die Abfrage als gültiges SQL zurückgegeben, basierend auf 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 '):]

3voto

chander Punkte 1758

Ich glaube, dies sollte funktionieren, wenn Sie PostgreSQL verwenden:

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())}')

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X