Django가 실행 중인 원시 SQL 쿼리를 확인하는 방법은 무엇입니까?
쿼리를 실행하는 동안 Django가 실행 중임을 SQL에 표시할 수 있는 방법이 있습니까?
문서 FAQ: "Django가 실행 중인 원시 SQL 쿼리를 확인하는 방법"을 참조하십시오.
django.db.connection.queries
:에 SQL목록을 나타냅니다 쿼리가 SQL쿼리의 목록을 포함합니다.
from django.db import connection
print(connection.queries)
쿼리 세트에는 실행할 쿼리를 포함하는 속성도 있습니다.
print(MyModel.objects.filter(name="my name").query)
쿼리 출력은 다음 이유로 유효하지 않습니다.
"Django는 실제로 매개 변수를 보간하지 않습니다. 쿼리 및 매개 변수를 데이터베이스 어댑터에 별도로 전송하여 적절한 작업을 수행합니다."
장고 버그 리포트 #17741에서.
따라서 쿼리 출력을 직접 데이터베이스로 전송해서는 안 됩니다.
만약 당신에게 질의를 다시 설정해야 할 지 많은 질문은 주어진 시간 안에 실행하고 있고 들어 예를을 사용할 수 있특정 기간 동안 몇 개의 쿼리가 실행 중인지 확인하기 위해 쿼리를 재설정해야 하는 경우를 참조하십시오.reset_queries
부터에서django.db
::
from django.db import reset_queries
reset_queries()
print(connection.queries)
>>> []
django-extensions에는 파라미터가 포함된 명령어 shell_plus가 있습니다.print-sql
./manage.py shell_plus --print-sql
django-shell에서 실행된 모든 쿼리가 인쇄됩니다.
예:
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>
debug_toolbar를 참조해 주세요.디버깅에 매우 편리합니다.
문서와 소스는 http://django-debug-toolbar.readthedocs.io/ 에서 구할 수 있습니다.
쿼리는 실제로 모델 API에 포함되어 있습니다.
q = Query.objects.values('val1','val2','val_etc')
print(q.query)
이 방법을 다루는 다른 답변은 없습니다.따라서 다음과 같습니다.
가장 유용하고 간편하며 신뢰할 수 있는 방법은 데이터베이스에 문의하는 것입니다.예를 들어 Postgres용 Linux에서는 다음을 수행할 수 있습니다.
sudo su postgres
tail -f /var/log/postgresql/postgresql-8.4-main.log
데이터베이스마다 절차가 조금씩 다릅니다.데이터베이스 로그에는 원시 SQL뿐만 아니라 django가 시스템에 배치한 연결 설정 또는 트랜잭션 오버헤드가 표시됩니다.
제공된 코드로 할 수 있지만, 디버깅 툴바 앱을 사용하는 것은 쿼리를 표시하는 데 매우 좋은 도구입니다.여기 github에서 다운로드 할 수 있어요.
그러면 지정된 페이지에서 실행된 모든 쿼리와 쿼리 소요 시간을 표시할 수 있습니다.또한 페이지 상의 쿼리 수와 빠른 검토를 위한 총 시간도 요약됩니다.이것은 장고 ORM이 뒤에서 무엇을 하는지 보고 싶을 때 좋은 도구입니다.그 밖에도, 마음에 들면 사용할 수 있는 기능이 많이 있습니다.
또 다른 옵션은 이 게시물에서 설명하는 settings.py의 로깅 옵션을 참조하십시오.
http://dabapps.com/blog/logging-sql-queries-django-13/
debug_debug를 지정하면 개발 서버의 각 페이지 로드가 느려지지만 로깅은 느려지지 않으므로 속도가 빨라집니다.출력을 콘솔 또는 파일로 덤프할 수 있으므로 UI가 좋지 않습니다.그러나 SQL이 많은 뷰의 경우 각 페이지 로드가 너무 느리기 때문에 debug_toolbar를 통해 SQL을 디버깅하고 최적화하는 데 오랜 시간이 걸릴 수 있습니다.
settings.py 파일에 다음 항목이 있는지 확인합니다.
django.core.context_processors.debug
에 기재되어에 나열된 있다CONTEXT_PROCESSORS
DEBUG=True
- 당신의 당신의.
IP
그 에서에INTERNAL_IPS
tuple태플
그럼 그 후,수 있습니다 할에 액세스에 접근해야 한다.sql_queries
변수.변수. 나는:이 것처럼 보이는 각 페이지에 대한 글을 덧붙였다.다음과 같은 각 페이지에 바닥글을 추가합니다.
{%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 %}
나는 가변 변수를다 찾았어요sql_time_sum
라인 행을 추가함으로써를 첨가하여
context_extras['sql_time_sum'] = sum([float(q['time']) for q in connection.queries])
django_src/django/core/debug_processors.py의 디버깅 함수로 이동합니다.
이를 위해 확장기능을 개발했기 때문에 뷰 기능에 데코레이터를 쉽게 배치하여 몇 개의 쿼리를 실행할 수 있는지 확인할 수 있습니다.
설치하는 방법:
$ pip install django-print-sql
콘텍스트 매니저로 사용하려면:
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()
데코레이터로 사용하려면:
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
덧붙이자면, 다음과 같은 질문이 있는 경우 django로 입력합니다.
MyModel.objects.all()
다음 작업을 수행합니다.
MyModel.objects.all().query.sql_with_params()
또는 다음과 같이 입력합니다.
str(MyModel.objects.all().query)
sql 문자열을 가져오다
이것은 매우 늦은 답이지만 다른 사람들은 검색을 통해 여기에 왔다.
나는 매우 단순한는 벌목 방법을 소개하고 추가매우 간단한방법을 소개합니다 로깅고 싶다.django.db.backends
목꾼. 화화
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'level': 'DEBUG',
},
},
}
또한 환경변수를 사용하여 레벨을 설정하고 있습니다.SQL 쿼리를 표시할 때는 환경변수를 설정하면 디버깅로그에 실제 쿼리가 표시됩니다.
Django SQL Sniffer는 Django ORM을 사용하는 프로세스에서 발생하는 원시 실행 쿼리를 표시(및 통계 표시)하기 위한 또 다른 대안입니다.지금까지 본 적이 없는 특정 사용 사례를 만족시키기 위해 구축했습니다. 즉, 다음과 같습니다.
- 대상 프로세스가 실행 중인 소스 코드에 대한 변경 없음(django 설정에서 새 앱을 등록할 필요 없음, 데코레이터 가져오기 등)
- 로깅 구성에 변경이 없음(예를 들어 설정이 적용되는 프로세스 전체가 아닌 특정 프로세스에 관심이 있기 때문)
- 타깃 프로세스를 재부팅할 필요가 없음(예를 들어 중요한 컴포넌트이기 때문에 재부팅 시 다운타임이 발생할 수 있음)
따라서 Django SQL Sniffer는 애드혹을 사용하여 이미 실행 중인 프로세스에 연결할 수 있습니다.그런 다음 실행된 쿼리를 "스니핑"하고 실행 시 콘솔에 출력합니다.툴이 정지되면 통계 요약이 몇 가지 가능한 메트릭(카운트, 최대 지속시간 및 총 결합 지속시간)에 따라 특이치 쿼리와 함께 표시됩니다.
다음은 Python 쉘에 첨부한 예시의 스크린샷입니다.
라이브 데모 및 자세한 내용은 github 페이지에서 확인하실 수 있습니다.
이 기능을 프로젝트의 앱 중 하나에 있는 util 파일에 넣었습니다.
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)))
그런 다음 필요할 때 Import하여 필요한 컨텍스트(보통 뷰)에서 호출합니다. 예를 들어 다음과 같습니다.
# ... 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
API 뷰(일반적으로 Django Rest Framework)가 있는 경우 템플릿 외부에서 이 작업을 수행하는 것이 좋습니다.
Postgre를 사용하고 있다면 이 방법이 효과가 있을 것이라고 생각합니다.SQL:
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())}')
다음은 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 '):]
사용할 수 있는 작은 조각을 만들었습니다.
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)
파라미터 함수(sql 쿼리 포함)로 검사하고 해당 함수를 호출하는 데 필요한 arg, kwargs를 사용합니다.그 결과 콘솔에 SQL 쿼리를 반환하고 인쇄하는 함수가 반환됩니다.
django에서 데이터베이스로 결과 쿼리를 가져오려면(올바른 파라미터 치환을 사용하여) 다음 함수를 사용할 수 있습니다.
from django.db import connection
def print_database_query_formatted(query):
sql, params = query.sql_with_params()
cursor = connection.cursor()
cursor.execute('EXPLAIN ' + sql, params)
db_query = cursor.db.ops.last_executed_query(cursor, sql, params).replace('EXPLAIN ', '')
parts = '{}'.format(db_query).split('FROM')
print(parts[0])
if len(parts) > 1:
parts = parts[1].split('WHERE')
print('FROM{}'.format(parts[0]))
if len(parts) > 1:
parts = parts[1].split('ORDER BY')
print('WHERE{}'.format(parts[0]))
if len(parts) > 1:
print('ORDER BY{}'.format(parts[1]))
# USAGE
users = User.objects.filter(email='admin@admin.com').order_by('-id')
print_database_query_formatted(users.query)
출력 예시
SELECT "users_user"."password", "users_user"."last_login", "users_user"."is_superuser", "users_user"."deleted", "users_user"."id", "users_user"."phone", "users_user"."username", "users_user"."userlastname", "users_user"."email", "users_user"."is_staff", "users_user"."is_active", "users_user"."date_joined", "users_user"."latitude", "users_user"."longitude", "users_user"."point"::bytea, "users_user"."default_search_radius", "users_user"."notifications", "users_user"."admin_theme", "users_user"."address", "users_user"."is_notify_when_buildings_in_radius", "users_user"."active_campaign_id", "users_user"."is_unsubscribed", "users_user"."sf_contact_id", "users_user"."is_agree_terms_of_service", "users_user"."is_facebook_signup", "users_user"."type_signup"
FROM "users_user"
WHERE "users_user"."email" = 'admin@admin.com'
ORDER BY "users_user"."id" DESC
다음 티켓 코멘트를 기반으로 합니다. https://code.djangoproject.com/ticket/17741#comment:4
일부 사용자 지정 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()
django.db.connection을 사용하여 쿼리를 표시합니다.쿼리
from django.db import connection
print(connection.queries)
QuerySet 개체에 대한 원시 SQL 쿼리 액세스
qs = MyModel.objects.all()
print(qs.query)
Django 2.2의 경우:
대부분의 답변이 사용 시 큰 도움이 되지 않았기 때문에./manage.py shell
마침내 답을 찾았다.★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
모든 쿼리를 표시하려면:
from django.db import connection
connection.queries
단일 쿼리에 대한 쿼리를 보려면:
q=Query.objects.all()
q.query.__str__()
q.query
물건을 전시하고 있을 뿐이에요.「 」의 __str__()
(문자열 표현)에 풀 쿼리가 표시되었습니다.
CREATE / UPDATE / DELETE / 명령어에 대한 SQL을 생성하려면 이 명령어는 Django에 있습니다.
from django.db.models import sql
def generate_update_sql(queryset, update_kwargs):
"""Converts queryset with update_kwargs
like : queryset.update(**update_kwargs) to UPDATE SQL"""
query = queryset.query.clone(sql.UpdateQuery)
query.add_update_values(update_kwargs)
compiler = query.get_compiler(queryset.db)
sql, params = compiler.as_sql()
return sql % params
from django.db.models import sql
def generate_delete_sql(queryset):
"""Converts select queryset to DELETE SQL """
query = queryset.query.chain(sql.DeleteQuery)
compiler = query.get_compiler(queryset.db)
sql, params = compiler.as_sql()
return sql % params
from django.db.models import sql
def generate_create_sql(model, model_data):
"""Converts queryset with create_kwargs
like if was: queryset.create(**create_kwargs) to SQL CREATE"""
not_saved_instance = model(**model_data)
not_saved_instance._for_write = True
query = sql.InsertQuery(model)
fields = [f for f in model._meta.local_concrete_fields if not isinstance(f, AutoField)]
query.insert_values(fields, [not_saved_instance], raw=False)
compiler = query.get_compiler(model.objects.db)
sql, params = compiler.as_sql()[0]
return sql % params
테스트 및 사용방법
def test_generate_update_sql_with_F(self):
qs = Event.objects.all()
update_kwargs = dict(description=F('slug'))
result = generate_update_sql(qs, update_kwargs)
sql = "UPDATE `api_event` SET `description` = `api_event`.`slug`"
self.assertEqual(sql, result)
def test_generate_create_sql(self):
result = generate_create_sql(Event, dict(slug='a', app='b', model='c', action='e'))
sql = "INSERT INTO `api_event` (`slug`, `app`, `model`, `action`, `action_type`, `description`) VALUES (a, b, c, e, , )"
self.assertEqual(sql, result)
Django의 경우 정확한 SQL 쿼리를 확인하는 가장 좋은 방법은 특정 데이터베이스 자체의 로그를 확인하는 것입니다.
예를 들어, 장고 웹사이트를 개발할 때 Postgre와의 원자거래 쿼리 "BEGIN"과 "COMMIT"를 확인하고 싶었다.SQL(버전 14)
그래서 정확한 Postgre 로그를 생성하기 위해SQL 쿼리에서 다음 코드를 "postgresql.conf" 끝에 추가했습니다.이 코드는 "C:\Program Files\PostgreSQL\14\data\postgresql.conf"를 선택합니다.
log_min_duration_statement = 0
아래 그림과 같이 위의 코드를 "postgresql.conf" 끝에 추가했습니다.
#------------------------------------------------------------------------------
# CUSTOMIZED OPTIONS
#------------------------------------------------------------------------------
# Add settings for extensions here
log_min_duration_statement = 0
그리고 Postgre를 조회한 후Django Admin을 통한 SQL 쿼리, Postgre를 통한 원자 트랜잭션 쿼리 "BEGIN" 및 "COMMIT"를 확인할 수 있었습니다."postgresql-2022-08-20_0000.log"를 열면 다음과 같은 SQL이 나타납니다.이거는 "C:\Program Files\PostgreSQL\14\data\log\postgresql-2022-08-20_000000.log"를 선택합니다.
2022-08-20 22:09:12.549 JST [26756] LOG: duration: 0.025 ms statement: BEGIN
2022-08-20 22:09:12.550 JST [26756] LOG: duration: 1.156 ms statement: SELECT "store_person"."id", "store_person"."first_name", "store_person"."last_name" FROM "store_person" WHERE "store_person"."id" = 33 LIMIT 21
2022-08-20 22:09:12.552 JST [26756] LOG: duration: 0.178 ms statement: UPDATE "store_person" SET "first_name" = 'Bill', "last_name" = 'Gates' WHERE "store_person"."id" = 33
2022-08-20 22:09:12.554 JST [26756] LOG: duration: 0.784 ms statement: INSERT INTO "django_admin_log" ("action_time", "user_id", "content_type_id", "object_id", "object_repr", "action_flag", "change_message") VALUES ('2022-08-20T13:09:12.553273+00:00'::timestamptz, 1, 20, '33', 'Bill Gates', 2, '[]') RETURNING "django_admin_log"."id"
2022-08-20 22:09:12.557 JST [26756] LOG: duration: 1.799 ms statement: COMMIT
또한 MSQL을 사용하여 정확한 MSQL(Microsoft SQL Server) 쿼리의 로그를 확인할 수도 있지만 SQLite에는 정확한 SQLite 쿼리의 로그를 저장하는 기능이 없는 것 같아 SQLite를 사용하여 정확한 SQLite 쿼리의 로그를 확인할 수 없습니다.
또한 콘솔 상의 정확한 SQL 쿼리 로그를 표시하기 위해 아래 코드를 "settings.py"에 추가함으로써 @GianMarco의 답변(swer)을 사용했습니다.
"settings.py"
LOGGING = {
'version': 1,
'filters': {
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
}
},
'handlers': {
'console': {
'level': 'DEBUG',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
}
},
'loggers': {
'django.db.backends': {
'level': 'DEBUG',
'handlers': ['console'],
}
}
}
단, 아래 그림과 같이 원자성 트랜잭션 쿼리 "BEGIN" 및 "COMMIT" 없이 SQL 쿼리 "SELECT", "UPDATE", "INSERT" 등을 표시했을 뿐입니다.
(0.000) SELECT "store_person"."id", "store_person"."first_name", "store_person"."last_name" FROM "store_person" WHERE "store_person"."id" = 33 LIMIT 21; args=(33,)
(0.000) UPDATE "store_person" SET "first_name" = 'Bill', "last_name" = 'Gates' WHERE "store_person"."id" = 33; args=('Bill', 'Gates', 33)
(0.000) INSERT INTO "django_admin_log" ("action_time", "user_id", "content_type_id", "object_id", "object_repr", "action_flag", "change_message") VALUES ('2022-08-20T13:55:19.226541+00:00'::timestamptz, 1, 20, '33', 'Bill Gates', 2, '[]') RETURNING "django_admin_log"."id"; args=(datetime.datetime(2022, 8, 20, 13, 55, 19, 226541, tzinfo=<UTC>), 1, 20, '33', 'Bill Gates', 2, '[]')
그리고 settings.py에 아래 코드를 추가하여 @geowa4의 답변(swer)을 사용하여 콘솔에 있는 정확한 SQL 쿼리의 로그를 표시하였습니다.* '장고==3.1.7' 사용 :
# "settings.py"
from django.db import connection
print(connection.queries) # Causes error
그러나 아래 오류가 발생했습니다.
django.core.exceptions.ImproperlyConfigured: settings.DATABASES is improperly configured. Please supply the ENGINE value. Check settings documentation for more details.
그래서 나는 "인쇄(연결을 제거했다.질의를)"아래에 다음 오류는 전혀 콘솔에 정확한 SQL쿼리의 어떠한 통나무들을 못 보여 줬어 해결되었다 보여 주고 있다.
# "settings.py"
from django.db import connection
# print(connection.queries) # Causes error
언급URL:https://stackoverflow.com/questions/1074212/how-to-see-the-raw-sql-queries-django-is-running
'itsource' 카테고리의 다른 글
Java 문자열 풀은 무엇이며 "s"는 새로운 문자열과 어떻게 다릅니까? (0) | 2022.09.16 |
---|---|
반복 문자로 채워진 가변 길이의 문자열을 만듭니다. (0) | 2022.09.16 |
느린 MYSQL 쿼리, 인덱스 이해 도움말 필요 (0) | 2022.09.16 |
JavaScript: 콜백 함수에 파라미터 전달 (0) | 2022.09.14 |
구조물의 특별한 점은 무엇입니까? (0) | 2022.09.14 |