Django'nun çalıştığı ham SQL sorgularını nasıl görebilirim?


307

Bir sorgu yaparken Django çalıştıran SQL göstermek için bir yolu var mı?

Yanıtlar:


372

Dokümanlara bakın SSS: " Django'nun çalıştığı ham SQL sorgularını nasıl görebilirim? "

django.db.connection.queries SQL sorgularının bir listesini içerir:

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

Querysets ayrıca yürütülecek sorguyu içeren bir queryözniteliğe sahiptir :

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

Sorgu çıktısının geçerli SQL olmadığını unutmayın, çünkü:

"Django asla parametreleri enterpolasyon etmez: sorguyu ve parametreleri ayrı ayrı, uygun işlemleri gerçekleştiren veritabanı bağdaştırıcısına gönderir."

Django hata raporundan # 17741 .

Bu nedenle, sorgu çıktısını doğrudan bir veritabanına göndermemelisiniz.


13
Bu yanıtı ileride kanıtlamak için Django'nun belgelerinin mevcut sürümünü bağlamanız gerekir: docs.djangoproject.com/en/dev/faq/models/…
Andre Miller

5
Mükemmel cevap. Ancak, str()dahili __str__()yöntemi çağıran belirtilen yerleşik Pythonian işlevinin kullanılması önerilir . Örneğin str(MyModel.objects.filter(name="my name").query) , IPython ve projenizin Django kabuğunu kullanmanızı tavsiye ederim. Sekme tamamlandığında nesne içgözlemi sağlanır. Django, iddialı adlandırma şemalarıyla tanındığı için, bu metodoloji çok yararlı olma eğilimindedir.
Lorenz Lo Sauer

7
Çıktısı şu Not querygeçerli bir SQL çünkü değil "Django gerçekte hiçbir zaman parametreleri interpolates. Uygun işlemleri gerçekleştirir veritabanı adaptörü, ayrı ayrı sorgu ve parametreleri gönderir" Kaynak: code.djangoproject.com/ticket/17741
gregoltsov

3
Sen kullanmalısınız @AndreMiller stabledeğil dev: Böyle Django şu anki sürümü olan ve bağlantıya, docs.djangoproject.com/en/stable/faq/models/...
Flimm

3
django.db.connection.queries boş liste döndürür
fantastory

61

Django uzantılarının bir parametresi olan shell_plus komutu varprint-sql

./manage.py shell_plus --print-sql

Django kabuğunda yürütülen tüm sorgular yazdırılır

Ör .:

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
--Print-sql veya SHELL_PLUS_PRINT_SQL = True ile kullanıyorum ve yardımcı olmuyor - hala sorguları göremiyorum. neden herhangi bir fikir? django 1.8
Dejell

1
Sorguları görmek için settings.py
dosyasında

50

Debug_toolbar'a bir bakın, hata ayıklama için çok kullanışlıdır.

Dokümantasyon ve kaynak http://django-debug-toolbar.readthedocs.io/ adresinde bulunabilir .

Hata ayıklama araç çubuğunun ekran görüntüsü


1
debug_toolbar özellikle bir SQL sözdizimi hatasıyla başarısız olan bir sorgunuz olduğunda kullanışlıdır; çalıştırmayı deneyen (ve başarısız olan) son sorguyu görüntüleyerek hata ayıklamayı kolaylaştırır.
scoopseven

Tek şey, tarayıcıda SQL sorguları görmektir. Testleri terminalden yaparsanız ve orada görmek isterseniz, bu geçerli bir çözüm değildir. Hala harika tho, bugüne kadar kullanıyorum.
Erdin Eray

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

print q.query

çok basit bir cevap! Nice
Espoir Murhabazi

Bu işlev kaldırıldı mı? Bunu m = MyModel.objects.get(...)takip ettiğimde işe yaramıyorm.query
sg

Çünkü martık bir sorgu kümesi değil. Kullan q = MyModel.objects.filter(...), sonra q.query, sonra m = q.get().
Brouwer

24

Başka hiçbir yanıt bu yöntemi kapsamaz, bu nedenle:

Açık ara en yararlı, basit ve güvenilir yöntemi veri tabanınıza sormaktır. Örneğin Postgres için Linux'ta şunları yapabilirsiniz:

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

Her veritabanı biraz farklı prosedürlere sahip olacaktır. Veritabanı günlüklerinde yalnızca ham SQL'i görmezsiniz, ancak herhangi bir bağlantı kurulumu veya işlem yükü django sisteme yerleştirilir.


8
ayarlamak unutmayın log_statement='all'yılında postgresql.confbu yöntem için.
RickyA

2
Eğer bulabilirsiniz postgresql.confçalıştırarakpsql -U postgres -c 'SHOW config_file'
kramer65

17

Sağlanan kod ile yapabilirsiniz, ancak hata ayıklama araç çubuğu uygulamasını kullanarak sorguları göstermek için harika bir araç olduğunu bulmak. Github'dan indirebilirsiniz buradan .

Bu, belirli bir sayfada çalıştırılan tüm sorguları sorgulama süresi ile birlikte gösterme seçeneği sunar. Ayrıca, hızlı bir inceleme için toplam süreyle birlikte bir sayfadaki sorguların sayısını da özetler. Bu, Django ORM'in perde arkasında ne yaptığını görmek istediğinizde harika bir araçtır. İsterseniz kullanabileceğiniz diğer birçok güzel özelliğe de sahiptir.


2
Bana bu en iyi sürüm gibi görünüyor: github.com/django-debug-toolbar/django-debug-toolbar
philfreo

15

Başka bir seçenek, bu gönderi tarafından açıklanan settings.py'deki günlük seçeneklerine bakın.

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

debug_toolbar geliştirici sunucunuzdaki her sayfa yükünü yavaşlatır, günlüğe kaydetme daha hızlı olmaz. Çıktılar konsol veya dosyaya dökülebilir, böylece kullanıcı arayüzü o kadar hoş değildir. Ancak çok sayıda SQL içeren görünümler için, her sayfa yükü çok yavaş olduğundan SQL'lerin hata ayıklaması ve debug_toolbar aracılığıyla optimize edilmesi uzun sürebilir.


Mükemmel! Araç çubuğu harika görünse de, bu cevabın kabul edilmiş olması gerektiğini düşünüyorum. İstediğim çözüm budur çünkü "manage.py runserver" konsolun SQL günlüğünü kaydetmesine izin verir ve "manage.py migrate" ile çalışır. İkincisi tablolarım oluşturulduğunda kesinlikle "silme çağlayan" ayarlanmadığını görmeme izin verin. Bu cevabın docs.djangoproject.com/en/1.9/topics/logging/…
LS

10

Settings.py dosyanızın şunlardan emin olduğundan emin olun:

  1. django.core.context_processors.debug listelenen CONTEXT_PROCESSORS
  2. DEBUG=True
  3. senin IPiçinde INTERNAL_IPStuple

O zaman sql_queriesdeğişkene erişiminiz olmalıdır . Her sayfaya aşağıdaki gibi bir altbilgi ekliyorum:

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

Değişkeni sql_time_sumsatır ekleyerek aldım

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

django_src / django / core / context_processors.py içindeki hata ayıklama işlevine


1
Ben sadece denedim ve (sql_time_sum bölümünü kaldırdıktan sonra) var: Şablonda adlandırılmış döngü yok. 'tek, çift' tanımlanmamış - ne eksik?
castaway

8

Bu amaçla bir uzantı geliştirdim, böylece görünüm işlevinize kolayca bir dekoratör koyabilir ve kaç sorgunun yürütüldüğünü görebilirsiniz.

Yüklemek:

$ pip install django-print-sql

İçerik yöneticisi olarak kullanmak için:

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

Dekoratör olarak kullanmak için:

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

PostgreSQL kullanıyorsanız bunun çalışması gerektiğine inanıyorum:

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

Bu, Python 2'de bile çalıştı. Yalnızca baskı (cursor.mogrify (* qs.query.sql_with_params ())) gibi bir refactor yeterlidir.
iChux

IIRC Cursor.mogrify bir dize döndürür, bu yüzden biçimlendirme için f dize kullanımını gereksiz olduğunu varsayalım ..
chander

2

Aşağıdaki sorgu, https://code.djangoproject.com/ticket/17741'e dayalı olarak sorguyu geçerli SQL olarak döndürür :

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

Kullanabileceğiniz küçük bir pasaj yaptım:

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)

İncelemek için parametre işlevi (sql sorguları içerir) ve bu işlevi çağırmak için gerekli kwargs olarak alır. Sonuç olarak hangi işlevin döndürdüğünü döndürür ve SQL sorgularını bir konsolda yazdırır.


1

Bu işlevi projemdeki uygulamalardan birinde bir util dosyasına koydum:

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

Sonra, gerektiğinde, ben sadece onu almak ve gerekli herhangi bir bağlam (genellikle bir görünüm) denir, örneğin:

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

Bunu şablonun dışında yapmak güzeldir, çünkü API görünümleriniz varsa (genellikle Django Rest Framework), orada da geçerlidir.


1

Django 2.2 için:

Cevapların çoğu kullanırken bana pek yardımcı olmadı ./manage.py shell. Sonunda cevabı buldum. Umarım bu birine yardımcı olur.

Tüm sorguları görüntülemek için:

from django.db import connection
connection.queries

Tek bir sorgunun sorgusunu görüntülemek için:

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

q.querysadece nesneyi benim için gösteriyorum. Kullanılması __str__()(String temsilini) tam sorgu sergiledi.


0

Django.db.connection.queries kullanarak Sorguları Görüntüleme

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

QuerySet nesnesinde ham SQL sorgusuna erişme

 qs = MyModel.objects.all()
 print(qs.query)

0

Sadece eklemek için, django, gibi bir sorgu varsa:

MyModel.objects.all()

yapmak:

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

sql dizesini almak için

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.