Làm cách nào tôi có thể thấy các truy vấn SQL thô Django đang chạy?


307

Có cách nào để hiển thị SQL mà Django đang chạy trong khi thực hiện truy vấn không?

Câu trả lời:


372

Xem Câu hỏi thường gặp về tài liệu: " Làm cách nào tôi có thể thấy các truy vấn SQL thô mà Django đang chạy? "

django.db.connection.queries chứa danh sách các truy vấn SQL:

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

Các truy vấn cũng có một querythuộc tính chứa truy vấn sẽ được thực thi:

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

Lưu ý rằng đầu ra của truy vấn không phải là SQL hợp lệ, bởi vì:

"Django thực sự không bao giờ nội suy các tham số: nó gửi truy vấn và các tham số riêng biệt đến bộ điều hợp cơ sở dữ liệu, thực hiện các hoạt động thích hợp."

Từ báo cáo lỗi Django # 17741 .

Do đó, bạn không nên gửi đầu ra truy vấn trực tiếp đến cơ sở dữ liệu.


13
Để chứng minh câu trả lời này trong tương lai, bạn nên liên kết phiên bản hiện tại của tài liệu của Django: docs.djangoproject.com/en/dev/faq/models/ trộm
Andre Miller

5
Câu trả lời chính xác. Tuy nhiên, nên sử dụng str()hàm Pythonia được chỉ định, dựng sẵn , gọi __str__()phương thức bên trong . ví dụ: str(MyModel.objects.filter(name="my name").query) tôi cũng khuyên bạn nên sử dụng IPython và shell Django trong dự án của bạn. Tab hoàn thành sau đó cung cấp nội quan đối tượng. Vì Django được biết đến với các kế hoạch đặt tên quyết đoán, phương pháp này có xu hướng rất hữu ích.
Lorenz Lo Sauer

7
Lưu ý rằng đầu ra của querySQL không hợp lệ, bởi vì "Django thực sự không bao giờ nội suy các tham số: nó gửi truy vấn và các tham số riêng biệt đến bộ điều hợp cơ sở dữ liệu, thực hiện các hoạt động thích hợp." Nguồn: code.djangoproject.com/ticket/17741
gregoltsov 7/07/14

3
@AndreMiller Bạn nên sử dụng stable, không dev, để liên kết với phiên bản hiện tại của Django, như thế này: docs.djangoproject.com/en/ sóng / faq / models / khăn
Flimm

3
django.db.connection.queries trả về danh sách trống
fantastory

61

Phần mở rộng Django có lệnh shell_plus với tham sốprint-sql

./manage.py shell_plus --print-sql

Trong django-shell, tất cả các truy vấn được thực hiện sẽ được in

Ví dụ.:

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
Tôi đang sử dụng nó với --print-sql hoặc với SHELL_PLUS_PRINT_Query = True và nó không hữu ích - Tôi vẫn không thể xem các truy vấn. bất cứ ý tưởng tại sao? django 1.8
Dejell

1
Bạn cần đặt DEBUG = True trong cài đặt của bạn để xem các truy vấn
Konstantin Voschanov

50

Hãy xem debug_toolbar , nó rất hữu ích để gỡ lỗi.

Tài liệu và nguồn có sẵn tại http://django-debug-toolbar.readthedocs.io/ .

Ảnh chụp màn hình của thanh công cụ gỡ lỗi


1
debug_toolbar đặc biệt hữu ích khi bạn có một truy vấn không thành công với lỗi cú pháp SQL; nó sẽ hiển thị truy vấn cuối cùng đã cố chạy (và không thành công), giúp gỡ lỗi dễ dàng hơn.
sốt dẻo

Điều duy nhất là bạn thấy các truy vấn SQL trên trình duyệt. Nếu bạn chạy thử nghiệm từ thiết bị đầu cuối và muốn xem nó ở đó, đây không phải là một giải pháp khả thi. Vẫn còn tho, tôi đã sử dụng nó cho đến ngày nay.
Erdin Eray

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

print q.query

Câu trả lời rất đơn giản! Nice
Espoir Murhabazi 17/07/19

Chức năng này đã được gỡ bỏ? Nó không hoạt động khi tôi làm m = MyModel.objects.get(...)theo saum.query
sg

Đó là bởi vì mkhông phải là một truy vấn nữa. Sử dụng q = MyModel.objects.filter(...), sau đó q.query, sau đó m = q.get().
Brouwer

24

Không có câu trả lời khác bao gồm phương pháp này, vì vậy:

Tôi thấy rằng phương pháp hữu ích, đơn giản và đáng tin cậy nhất là hỏi cơ sở dữ liệu của bạn. Ví dụ: trên Linux cho Postgres bạn có thể làm:

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

Mỗi cơ sở dữ liệu sẽ có thủ tục hơi khác nhau. Trong nhật ký cơ sở dữ liệu, bạn sẽ thấy không chỉ SQL thô, mà bất kỳ thiết lập kết nối hoặc django giao dịch nào đang được đặt trên hệ thống.


8
đừng quên để thiết lập log_statement='all'trong postgresql.confcho phương pháp này.
RickyA

2
Bạn có thể tìm thấy bạn postgresql.confbằng cách chạypsql -U postgres -c 'SHOW config_file'
kramer65

17

Mặc dù bạn có thể làm điều đó với mã được cung cấp, tôi thấy rằng sử dụng ứng dụng thanh công cụ gỡ lỗi là một công cụ tuyệt vời để hiển thị các truy vấn. Bạn có thể tải nó từ github tại đây .

Điều này cung cấp cho bạn tùy chọn hiển thị tất cả các truy vấn đã chạy trên một trang nhất định cùng với thời gian truy vấn đã thực hiện. Nó cũng tổng hợp số lượng truy vấn trên một trang cùng với tổng thời gian để đánh giá nhanh. Đây là một công cụ tuyệt vời, khi bạn muốn xem những gì Django ORM làm đằng sau hậu trường. Nó cũng có rất nhiều tính năng hay khác, mà bạn có thể sử dụng nếu bạn thích.


2
Có vẻ như đây là phiên bản tốt nhất: github.com/django-debug-toolbar/django-debug-toolbar
philfreo

15

Một tùy chọn khác, xem các tùy chọn đăng nhập trong settings.txt được mô tả bởi bài đăng này

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

debug_toolbar làm chậm tải mỗi trang trên máy chủ dev của bạn, đăng nhập không vì thế nó nhanh hơn. Đầu ra có thể được đổ vào bàn điều khiển hoặc tập tin, vì vậy giao diện người dùng không đẹp. Nhưng đối với các chế độ xem có nhiều SQL, có thể mất nhiều thời gian để gỡ lỗi và tối ưu hóa các SQL thông qua debug_toolbar vì mỗi lần tải trang quá chậm.


Thông minh! Trong khi thanh công cụ trông tuyệt vời, tôi nghĩ câu trả lời này nên được chấp nhận. Đây là giải pháp tôi muốn bởi vì nó cho phép "Manage.txt ranerver" đăng nhập SQL vào bảng điều khiển và nó hoạt động với "Manage.txt di chuyển". Cái sau cho tôi thấy rằng "on xóa tầng" chắc chắn không được đặt khi các bảng của tôi được tạo. Điều đáng chú ý là câu trả lời này dựa trên docs.djangoproject.com/en/1.9/topics/logging/ mẹo
LS

10

Nếu bạn chắc chắn rằng tệp cài đặt của bạn có:

  1. django.core.context_processors.debug được liệt kê trong CONTEXT_PROCESSORS
  2. DEBUG=True
  3. IPtrong INTERNAL_IPStuple của bạn

Sau đó, bạn nên có quyền truy cập vào các sql_queriesbiến. Tôi nối một chân trang vào mỗi trang giống như thế này:

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

Tôi đã nhận được biến sql_time_sumbằng cách thêm dòng

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

đến chức năng gỡ lỗi trong django_src / django / core / context_ Processors.py.


1
Tôi vừa thử điều này và (đã loại bỏ phần sql_time_sum), nhận được: Không có chu kỳ được đặt tên trong mẫu. 'lẻ, thậm chí' không được xác định - tôi đang thiếu gì?
castaway

8

Tôi đã phát triển một tiện ích mở rộng cho mục đích này, vì vậy bạn có thể dễ dàng đặt một trình trang trí vào chức năng xem của mình và xem có bao nhiêu truy vấn được thực hiện.

Để cài đặt:

$ pip install django-print-sql

Để sử dụng làm trình quản lý bối cảnh:

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

Để sử dụng như trang trí:

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

Tôi tin rằng điều này nên hoạt động nếu bạn đang sử dụng 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())}')

Điều này hoạt động ngay cả trong Python 2. Chỉ một bộ tái cấu trúc như in (con trỏ.mogrify (* qs.query.sql_with_params ())) là tất cả những gì nó cần.
iChux

IIRC Cthon.mogrify trả về một chuỗi, vì vậy tôi cho rằng việc sử dụng chuỗi f để định dạng là không cần thiết ..
chander

2

Sau đây trả về truy vấn dưới dạng SQL hợp lệ, dựa trên 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

Tôi đã tạo một đoạn nhỏ bạn có thể sử dụng:

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)

Nó có chức năng như tham số (chứa các truy vấn sql) để kiểm tra và lập luận, các kwarg cần thiết để gọi hàm đó. Kết quả là nó trả về hàm nào trả về và in các truy vấn SQL trong bàn điều khiển.


1

Tôi đặt chức năng này trong một tệp sử dụng trong một trong các ứng dụng trong dự án của mình:

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

Sau đó, khi cần, tôi chỉ cần nhập nó và gọi nó từ bất kỳ bối cảnh nào (thường là chế độ xem) là cần thiết, ví dụ:

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

Thật tuyệt khi làm điều này bên ngoài mẫu bởi vì sau đó nếu bạn có chế độ xem API (thường là Django Rest Framework), thì nó cũng có thể áp dụng được.


1

Đối với Django 2.2:

Vì hầu hết các câu trả lời không giúp tôi nhiều khi sử dụng ./manage.py shell. Cuối cùng tôi cũng tìm được câu trả lời. Hy vọng điều này sẽ giúp cho một ai đó.

Để xem tất cả các truy vấn:

from django.db import connection
connection.queries

Để xem truy vấn cho một truy vấn duy nhất:

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

q.querychỉ hiển thị các đối tượng cho tôi. Sử dụng __str__()(Biểu diễn chuỗi) hiển thị toàn bộ truy vấn.


0

Xem Truy vấn bằng django.db.connection.queries

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

Truy cập truy vấn SQL thô trên đối tượng Queryset

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

0

Chỉ cần thêm, trong django, nếu bạn có một truy vấn như:

MyModel.objects.all()

làm:

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

để có được chuỗi sql

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.