是否有一种方法可以在执行查询时显示Django正在运行的SQL ?


当前回答

你可以使用连接。在Django中运行原始SQL查询,如下所示:

# "store/views.py"

from django.db import transaction
from .models import Person
from django.db import connection
from django.http import HttpResponse

@transaction.atomic
def test(request):
    Person.objects.create(name="John") # INSERT
    
    qs = Person.objects.select_for_update().get(name="John") # SELECT FOR UPDATE
    qs.name = "Tom"
    qs.save() # UPDATE
    qs.delete() # DELETE
                 
    for query in connection.queries: # Here
        print(query)

    return HttpResponse("Test")

然后,原始查询打印在控制台,如下所示:

{'sql': 'INSERT INTO "store_person" ("name") VALUES (\'John\') RETURNING "store_person"."id"', 'time': '0.000'}
{'sql': 'SELECT "store_person"."id", "store_person"."name" FROM "store_person" WHERE "store_person"."name" = \'John\' LIMIT 21 FOR UPDATE', 'time': '0.000'}      
{'sql': 'UPDATE "store_person" SET "name" = \'Tom\' WHERE "store_person"."id" = 179', 'time': '0.000'}
{'sql': 'DELETE FROM "store_person" WHERE "store_person"."id" IN (179)', 'time': '0.000'}
[24/Dec/2022 06:29:32] "GET /store/test/ HTTP/1.1" 200 9

然后,把reset_queries()放在Person.objects.select_for_update()之后,如果你想只得到UPDATE和DELETE查询,而没有INSERT和SELECT FOR UPDATE查询,如下所示:

# "store/views.py"

from django.db import transaction
from .models import Person
from django.db import reset_queries
from django.db import connection
from django.http import HttpResponse

@transaction.atomic
def test(request):
    Person.objects.create(name="John") # INSERT
    
    qs = Person.objects.select_for_update().get(name="John") # SELECT FOR UPDATE
    reset_queries() # Here
    qs.name = "Tom"
    qs.save() # UPDATE
    qs.delete() # DELETE
                 
    for query in connection.queries: # Here
        print(query)

    return HttpResponse("Test")

然后,只打印UPDATE和DELETE查询,不打印INSERT和SELECT FOR UPDATE查询,如下所示:

{'sql': 'UPDATE "store_person" SET "name" = \'Tom\' WHERE "store_person"."id" = 190', 'time': '0.000'}
{'sql': 'DELETE FROM "store_person" WHERE "store_person"."id" IN (190)', 'time': '0.000'}
[24/Dec/2022 07:00:01] "GET /store/test/ HTTP/1.1" 200 9

其他回答

下面基于https://code.djangoproject.com/ticket/17741:返回有效的SQL查询

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

使用django.db.connection.queries查看查询

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

访问QuerySet对象上的原始SQL查询

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

另一个选项,请参阅本文中描述的settings.py中的日志记录选项

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

Debug_toolbar会降低开发服务器上每个页面的加载速度,而日志记录则不会,因此速度更快。输出可以转储到控制台或文件,所以UI不是很好。但是对于包含大量sql的视图,通过debug_toolbar调试和优化sql可能需要很长时间,因为每个页面加载都非常慢。

这是一个很晚的回答,但其他的都是通过搜索得到的。

我想介绍一种日志记录方法,非常简单;在settings .py中添加django.db.backends logger

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'level': 'DEBUG',
        },
    },
}

我还使用了一个环境变量来设置级别。 所以当我想看到SQL查询时,我只是设置了环境变量,调试日志显示了实际的查询。

如果您需要为一些自定义SQL重用查询,还有另一种非常有用的方法。我曾在一个分析应用程序中使用过这种方法,它远远超出了Django的ORM所能轻松完成的范围,所以我将ORM生成的SQL作为子查询包含进来。

from django.db import connection
from myapp.models import SomeModel

queryset = SomeModel.objects.filter(foo='bar')

sql_query, params = queryset.query.as_sql(None, connection)

这将为您提供带有占位符的SQL,以及可以使用的带有查询参数的元组。你可以直接把它传递给DB:

with connection.connection.cursor(cursor_factory=DictCursor) as cursor:
    cursor.execute(sql_query, params)
    data = cursor.fetchall()