web-dev-qa-db-fra.com

Comment puis-je voir les requêtes SQL brutes exécutées par Django?

Existe-t-il un moyen de montrer le code SQL exécuté par Django lors de l'exécution d'une requête?

232
spence91

Voir la FAQ de la documentation: " Comment puis-je voir les requêtes SQL brutes que Django exécute? "

Django.db.connection.queries contient une liste des requêtes SQL:

from Django.db import connection
print connection.queries

Les groupes de requêtes ont également un attribut query contenant la requête à exécuter:

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

Notez que la sortie de la requête n'est pas un code SQL valide, car:

"Django n'interpole jamais réellement les paramètres: il envoie la requête et les paramètres séparément à l'adaptateur de base de données, qui effectue les opérations appropriées."

D'après le rapport de bogue Django # 17741 .

De ce fait, vous ne devez pas envoyer le résultat de la requête directement à une base de données.

291
geowa4

Jetez un coup d’œil à debug_toolbar, c’est très utile pour le débogage.

La documentation et les sources sont disponibles sur http://Django-debug-toolbar.readthedocs.io/ .

 Screenshot of debug toolbar

39
Glader

Django-extensions a une commande Shell_plus avec un paramètre print-sql

./manage.py Shell_plus --print-sql

Dans Django-Shell, toutes les requêtes exécutées seront imprimées.

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>
32
Patrick Z

Bien que vous puissiez le faire avec le code fourni, je trouve que l’application de la barre d’outils de débogage est un excellent outil pour afficher les requêtes. Vous pouvez le télécharger depuis github ici .

Cela vous donne la possibilité d'afficher toutes les requêtes exécutées sur une page donnée ainsi que le temps nécessaire à l'interrogation. Il résume également le nombre de requêtes sur une page, ainsi que le temps total nécessaire pour une révision rapide. C’est un excellent outil lorsque vous voulez voir ce que l’ORM Django fait en coulisse. Il a également beaucoup d'autres fonctionnalités de Nice, que vous pouvez utiliser si vous le souhaitez.

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

print q.query
16
jgabrielsk8

Aucune autre réponse ne couvre cette méthode, alors:

Je trouve de loin que la méthode la plus utile, la plus simple et la plus fiable consiste à demander votre base de données. Par exemple, sur Linux pour Postgres, vous pouvez effectuer les tâches suivantes:

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

Chaque base de données aura une procédure légèrement différente. Dans les journaux de la base de données, vous verrez non seulement le SQL brut, mais également toute configuration de connexion ou surcharge de transaction que Django place sur le système.

16
Bryce

Une autre option, voir les options de journalisation dans settings.py décrite par cet article.

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

debug_toolbar ralentit le chargement de chaque page sur votre serveur dev, la journalisation ne le ralentit pas, donc c'est plus rapide. Les sorties peuvent être sauvegardées dans la console ou dans un fichier, l'interface utilisateur n'est donc pas aussi agréable. Toutefois, pour les vues contenant beaucoup de SQL, le débogage et l'optimisation de ces derniers par le biais de debug_toolbar peuvent prendre du temps, car chaque chargement de page est très lent.

12
Overclocked

Si vous vous assurez que votre fichier settings.py a:

  1. Django.core.context_processors.debug répertorié dans CONTEXT_PROCESSORS
  2. DEBUG=True
  3. votre IP dans le INTERNAL_IPS Tuple

Ensuite, vous devriez avoir accès à la variable sql_queries. J'ajoute un pied de page à chaque page qui ressemble à ceci:

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

J'ai obtenu la variable sql_time_sum en ajoutant la ligne 

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

à la fonction de débogage dans Django_src/Django/core/context_processors.py.

10
Mike Howsden

J'ai développé une extension à cette fin, vous pouvez donc facilement mettre un décorateur sur votre fonction de vue et voir combien de requêtes sont exécutées.

À installer:

$ pip install Django-print-sql

Pour utiliser en tant que gestionnaire de contexte:

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

A utiliser comme décorateur:

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

5
rabbit.aaron

Je crois que cela devrait fonctionner si vous utilisez 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())}')
1
chander

Ce qui suit renvoie la requête en tant que code SQL valide, basé sur 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 '):]
1
Flash

J'ai pu voir les requêtes échouées simplement en faisant:

tail -f /var/log/postgresql/*

Cela supposait que postgres 10.6, ubuntu 18.04+, python3 +, Django2 + et que la journalisation avait été activée dans postgres.

0
jmunsch

J'ai fait un petit extrait que vous pouvez utiliser:

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)

Il prend comme fonction de paramètres (contient des requêtes SQL) à inspecter et args, kwargs nécessaires pour appeler cette fonction. Il en résulte que la fonction retourne et imprime les requêtes SQL dans une console.

0
turkus