Bagaimana saya bisa melihat query SQL mentah yang dijalankan Django?


307

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

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.


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>

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


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

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.


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.


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.


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.


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


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

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 '):]

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.


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.


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.


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)

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.