Просмотр SQL запросов, сделанных Django ORM

Частая задача, которая встаёт при использовании Django в серьёзных проектах - знать, какие именно запросы генерирует Django ORM. Неподготовленного человека просмотр этих SQL запросов (вернее их количества) может привести в шок ) Например, если поле объекта является ForeignKey(null=True), то при выводе этого поля у множества объектов, на каждый объект будет делаться запрос для этого поля и даже select_related() не поможет.

Подобные проблемы решаются различными ухищрениями типа:
- http://web-brains.com/2007/12/06/selecte_related_and_foreign_key/
- http://piranha.org.ua/blog/2007/10/31/related-objects/

Но рассказать я хочу не про ухищрения, о которых и так уже рассказано, а о том, как можно удобно просматривать SQL запросы для каждой конкретной страницы сайта, сделанного на Django.

Решение очевидно: надо сделать templatetag, который, будет выводить эти запросы ) Как гласит официальная документация запросы, которые сделал django ORM, можно извлечь из django.db.connection.queries (settings.DEBUG должен быть True). Т.е. логика template tag получается очень простой: получить sql запросы и передать их в шаблон. Конечно, если выводить полотно чёрнобелых запросов на каждой странице, это будет неэстетично и утомительно для мозга, поэтому я сделал несколько плюшек: разбивание длинных строк запроса на несколько строк, подсветка через pygments (опционально), скрытие блока запросов по умолчание и показ их по щелчку на специальной ссылке.

Код в студию!

Логика тэга orm_debug:


@register.inclusion_tag('site/orm_debug.html')
def orm_debug():
import re
try:
from pygments import highlight
from pygments.lexers import SqlLexer
from pygments.formatters import HtmlFormatter
pygments_installed = True
except ImportError:
pygments_installed = False

from django.db import connection
queries = connection.queries
query_time = 0
query_count = 0
for query in queries:
query_time += float(query['time'])
query_count += int(1)
query['sql'] = re.sub(r'(FROM|WHERE)', '\n\\1', query['sql'])
query['sql'] = re.sub(r'((?:[^,]+,){3})', '\\1\n ', query['sql'])
if pygments_installed:
formatter = HtmlFormatter()
query['sql'] = highlight(query['sql'], SqlLexer(), formatter)
pygments_css = formatter.get_style_defs()
else:
pygments_css = ''
return {
'pygments_css': pygments_css,
'pygments_installed': pygments_installed,
'query_time': query_time,
'query_count': query_count,
'queries': queries}


Шаблон тэга orm_debug:


<style type="text/css">
{% if pygments_css %}
{{ pygments_css }}
{% endif %}
#orm-debug-body {
display: none;
color: #e0e0e0;
background-color: #101010;
font-size: 15px;
line-height: 16px;
padding: 1px 1em 1em 1em;
}
#orm-debug-body p {
margin: 0;
}
#orm-debug-body pre {
margin: 0;
}
#orm-debug-body .query-info {
margin-top: 1em;
margin-bottom: 0.2em;
}
</style>
<div id="orm-debug-head">
<a href="#" onclick="document.getElementById('orm-debug-body').style.display = 'block'">debug</a>
sql count: {{ query_count }}, sql time: {{ query_time }}
</div>
<div id="orm-debug-body">
{% for query in queries %}
<div class="code">
<div class="query-info">time: {{ query.time }}</div>
{% if not pygments_installed %}<pre>{% endif %}
{{ query.sql|safe|linebreaks }}
{% if not pygments_installed %}</pre>{% endif %}
</div>
{% endfor %}
</div>


Как использовать этот тэг? Очень просто: кладёте куда надо, подключаете, потом в шаблоне страницы в самом-самом низу пишете {% orm_debug %}. В этом месте появится ссылочка, а также инфа по суммарному времени и количестве запросов. После щелчка на ссылке будет отрываться блок SQL запросов.
Add post to:   Google Slashdot Yahoo Digg Technorati Delicious Bobrdobr.ru Newsland.ru Smi2.ru Rumarkz.ru Vaau.ru Memori.ru Rucity.com Moemesto.ru News2.ru Mister-Wong.ru Yandex.ru Myscoop.ru 100zakladok.ru
Make comment

Comments

  • Как я уже сказал на форуме у Ивана, очень зачётная вещь. Всё просто и доступно. +1

  • На самом деле я к этой штуке успел ещё одну мега вещь прикрутить, попозже статью переделаю. В общем, через AJAX можно смотреть explain каждого SQL-запроса )

  • Жду с нетерпением …

  • Спасибо, очень пригодилось.

    ..bw

comment submission form

Required. 30 chars of fewer.

Required.

captcha image Please, enter symbols, which you see on the image