Bagaimana saya bisa melihat query SQL mentah yang dijalankan Django?

307

Apakah ada cara untuk menunjukkan SQL bahwa Django sedang berjalan saat melakukan query?

spence91
sumber

Jawaban:

372

Lihat FAQ dokumen: " Bagaimana saya bisa melihat query SQL mentah yang dijalankan Django? "

django.db.connection.queries berisi daftar kueri SQL:

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

Querysets juga memiliki queryatribut yang berisi kueri yang akan dieksekusi:

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

Perhatikan bahwa output kueri tidak valid SQL, karena:

"Django tidak pernah benar-benar menginterpolasi parameter: ia mengirimkan permintaan dan parameter secara terpisah ke adaptor basis data, yang melakukan operasi yang sesuai."

Dari laporan bug Django # 17741 .

Karena itu, Anda tidak boleh mengirim output permintaan langsung ke database.

geowa4
sumber
13
Untuk bukti di masa depan jawaban ini, Anda sebaiknya menautkan versi dokumentasi Django saat ini: docs.djangoproject.com/en/dev/faq/models/…
Andre Miller
5
Jawaban yang bagus Namun, disarankan untuk menggunakan str()fungsi Pythonian yang ditentukan dan dibangun , yang memanggil __str__()metode internal . misalnya str(MyModel.objects.filter(name="my name").query) saya juga akan merekomendasikan menggunakan IPython dan shell Django dari proyek Anda. Tab selesai kemudian memberikan introspeksi objek. Karena Django dikenal dengan skema penamaan yang tegas, metodologi ini cenderung sangat berguna.
Lorenz Lo Sauer
7
Perhatikan bahwa output dari querytidak valid SQL, karena "Django tidak pernah benar-benar menginterpolasi parameter: ia mengirimkan permintaan dan parameter secara terpisah ke adaptor database, yang melakukan operasi yang sesuai." Sumber: code.djangoproject.com/ticket/17741
gregoltsov
3
@AndreMiller Anda harus menggunakan stable, bukan dev, untuk menaut ke versi Django saat ini, seperti ini: docs.djangoproject.com/en/stable/faq/models/…
Flimm
3
django.db.connection.queries mengembalikan daftar kosong
fantastory
61

Django-ekstensi memiliki perintah shell_plus dengan parameterprint-sql

./manage.py shell_plus --print-sql

Dalam django-shell semua query yang dieksekusi akan dicetak

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>
Patrick Z
sumber
1
Saya menggunakannya dengan --print-sql atau dengan SHELL_PLUS_PRINT_SQL = Benar dan itu tidak membantu - Saya masih tidak dapat melihat kueri. ada yang tahu kenapa? django 1.8
Dejell
1
Anda perlu mengatur DEBUG = Benar di pengaturan Anda
.py
50

Lihatlah debug_toolbar , ini sangat berguna untuk debugging.

Dokumentasi dan sumber tersedia di http://django-debug-toolbar.readthedocs.io/ .

Cuplikan layar bilah alat debug

Glader
sumber
1
debug_toolbar sangat berguna ketika Anda memiliki kueri yang gagal dengan kesalahan sintaks SQL; itu akan menampilkan permintaan terakhir yang mencoba untuk menjalankan (dan gagal), membuatnya lebih mudah untuk di-debug.
scoopseven
Satu-satunya hal adalah Anda melihat query SQL di browser. Jika Anda menjalankan tes dari terminal dan ingin melihatnya di sana, ini bukan solusi yang layak. Masih hebat, saya sudah menggunakannya sampai hari ini.
Erdin Eray
24
q = Query.objects.values('val1','val2','val_etc')

print q.query
jgabrielsk8
sumber
jawaban yang sangat sederhana! Nice
Espoir Murhabazi
Apakah fungsi ini telah dihapus? Ini tidak bekerja ketika saya m = MyModel.objects.get(...)diikuti olehm.query
sg
Itu karena mbukan queryset lagi. Gunakan q = MyModel.objects.filter(...), lalu q.query, lalu m = q.get().
Brouwer
24

Tidak ada jawaban lain yang mencakup metode ini, jadi:

Sejauh ini saya menemukan metode yang paling berguna, sederhana, dan dapat diandalkan untuk menanyakan basis data Anda. Misalnya di Linux untuk Postgres yang mungkin Anda lakukan:

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

Setiap basis data akan memiliki prosedur yang sedikit berbeda. Dalam log basis data Anda tidak hanya akan melihat SQL mentah, tetapi juga pengaturan koneksi atau django overhead transaksi yang ditempatkan pada sistem.

Bryce
sumber
8
jangan lupa untuk mengatur log_statement='all'dalam postgresql.confuntuk metode ini.
RickyA
2
Anda dapat menemukan Anda postgresql.confdengan menjalankanpsql -U postgres -c 'SHOW config_file'
kramer65
17

Meskipun Anda dapat melakukannya dengan kode yang disediakan, saya menemukan bahwa menggunakan aplikasi bilah alat debug adalah alat yang hebat untuk menampilkan kueri. Anda dapat mengunduhnya dari github di sini .

Ini memberi Anda opsi untuk menampilkan semua kueri yang berlari pada halaman tertentu bersamaan dengan waktu untuk kueri. Itu juga meringkas jumlah pertanyaan pada halaman bersama dengan total waktu untuk tinjauan cepat. Ini adalah alat yang hebat, ketika Anda ingin melihat apa yang dilakukan ORANG Django di belakang layar. Ini juga memiliki banyak fitur bagus lainnya, yang dapat Anda gunakan jika Anda suka.

googletorp
sumber
2
Menurut saya ini adalah versi terbaik: github.com/django-debug-toolbar/django-debug-toolbar
philfreo
15

Opsi lain, lihat opsi masuk dalam pengaturan.py yang dijelaskan oleh posting ini

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

debug_toolbar memperlambat setiap pemuatan halaman di server dev Anda, logging tidak jadi lebih cepat. Keluaran dapat dibuang ke konsol atau file, sehingga UI tidak sebaik. Tetapi untuk tampilan dengan banyak SQL, perlu waktu lama untuk debug dan mengoptimalkan SQL melalui debug_toolbar karena setiap halaman memuat sangat lambat.

Overclock
sumber
Luar biasa! Sementara bilah alat terlihat bagus, saya pikir jawaban ini harus diterima. Ini adalah solusi yang saya inginkan karena memungkinkan "manage.py runserver" log SQL ke konsol dan bekerja dengan "manage.py migrasi". Yang terakhir biarkan saya melihat bahwa "pada penghapusan kaskade" jelas tidak diatur ketika tabel saya dibuat. Patut dicatat bahwa jawaban ini didasarkan pada docs.djangoproject.com/en/1.9/topics/logging/…
LS
10

Jika Anda memastikan file settings.py Anda memiliki:

  1. django.core.context_processors.debug tercantum dalam CONTEXT_PROCESSORS
  2. DEBUG=True
  3. Anda IPdi INTERNAL_IPStuple

Maka Anda harus memiliki akses ke sql_queriesvariabel. Saya menambahkan catatan kaki ke setiap halaman yang terlihat seperti ini:

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

Saya mendapatkan variabel sql_time_sumdengan menambahkan baris

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

ke fungsi debug di django_src / django / core / context_processors.py.

Mike Howsden
sumber
1
Saya baru saja mencoba ini, dan (setelah menghapus bagian sql_time_sum), mendapat: Tidak ada siklus bernama dalam template. 'aneh, datar' tidak didefinisikan - apa yang saya lewatkan?
terbuang
8

Saya mengembangkan ekstensi untuk tujuan ini, sehingga Anda dapat dengan mudah menempatkan dekorator pada fungsi tampilan Anda dan melihat berapa banyak kueri yang dieksekusi.

Untuk memasang:

$ pip install django-print-sql

Untuk digunakan sebagai manajer konteks:

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

Untuk digunakan sebagai 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

rabbit.aaron
sumber
3

Saya percaya ini harus bekerja jika Anda menggunakan 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())}')
chander
sumber
Ini bekerja bahkan dalam Python 2. Hanya refactor seperti cetak (cursor.mogrify (* qs.query.sql_with_params ())) yang dibutuhkan.
iChux
IIRC Cursor.mogrify mengembalikan sebuah string, jadi saya kira penggunaan string f untuk memformat berlebihan ..
chander
2

Berikut ini mengembalikan kueri sebagai SQL yang valid, berdasarkan 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 '):]
Flash
sumber
2

Saya telah membuat cuplikan kecil yang dapat Anda gunakan:

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)

Dibutuhkan sebagai fungsi parameter (berisi kueri sql) untuk memeriksa dan berargumen, kwargs diperlukan untuk memanggil fungsi itu. Sebagai hasilnya mengembalikan fungsi apa dan mencetak permintaan SQL di konsol.

turkus
sumber
1

Saya menempatkan fungsi ini dalam file util di salah satu aplikasi di proyek saya:

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

Kemudian, ketika dibutuhkan, saya hanya mengimpornya dan menyebutnya dari konteks apa pun (biasanya tampilan) yang diperlukan, misalnya:

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

Sangat menyenangkan untuk melakukan ini di luar template karena jika Anda memiliki tampilan API (biasanya Django Rest Framework), itu berlaku juga di sana.

getup8
sumber
1

Untuk Django 2.2:

Karena sebagian besar jawaban tidak banyak membantu saya ketika menggunakan ./manage.py shell. Akhirnya saya menemukan jawabannya. Semoga ini bisa membantu seseorang.

Untuk melihat semua pertanyaan:

from django.db import connection
connection.queries

Untuk melihat permintaan untuk satu permintaan:

q=Query.objects.all()
q.query.__str__()

q.queryhanya menampilkan objek untukku. Menggunakan __str__()(Representasi string) ditampilkan permintaan penuh.

goutham_mi3
sumber
0

Lihat Query menggunakan django.db.connection.queries

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

Akses query SQL mentah pada objek QuerySet

 qs = MyModel.objects.all()
 print(qs.query)
Muhammad Parwej
sumber
0

Untuk menambahkan, dalam Django, jika Anda memiliki pertanyaan seperti:

MyModel.objects.all()

melakukan:

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

untuk mendapatkan string sql

Robert Wallace
sumber