23 августа 2012 г. Django MySQL Релизы Python EN In English

Релизнул встраиваемое приложение "django-sql-stacktrace"

Это приложение записывает python stack trace в SQL-запрос как коментарий. Это бывает полезно во время откладки проекта, когда вы видите много SQL-запросов и не понимаете откуда они были вызваны.

PyPI: django-sql-stacktrace

Для примера, вы попали в новый проект и вас попросили исправить проблему с большим количеством запросов к БД. Вы открываете processlist ("mysqladmin processlist --verbose") и видите множество различных запросов:

...

SELECT COUNT(*) FROM `films_film` INNER JOIN `films_year` ON (`films_film`.`year_id` = 
`films_year`.`id`) WHERE (`films_film`.`status` = 'published' AND `films_year`.`id` IS NOT NULL);

SELECT `blogs_post`.`id`, `blogs_post`.`blog_id`, `blogs_post`.`title`, `blogs_post`.`slug`, 
`blogs_post`.`status`, `blogs_post`.`created`, `blogs_post`.`updated`, 
`blogs_post`.`published`, `blogs_post`.`description`, `blogs_post`.`thumbnail`, 
`blogs_post`.`content`, `blogs_post`.`count_of_views`, `blogs_post`.`source_content`, 
`blogs_post`.`source_published`, `blogs_post`.`source_count_views`, 
`blogs_post`.`source_author_of_content`, `blogs_post`.`source_author_of_photo`, 
`blogs_post`.`source_keywords`, `blogs_post`.`source_url` FROM `blogs_post` WHERE 
`blogs_post`.`status` = 'published' ORDER BY `blogs_post`.`published` DESC LIMIT 4;

SELECT `social_auth_usersocialauth`.`id`, `social_auth_usersocialauth`.`user_id`, 
`social_auth_usersocialauth`.`provider`, `social_auth_usersocialauth`.`uid`, 
`social_auth_usersocialauth`.`extra_data` FROM `social_auth_usersocialauth` WHERE 
`social_auth_usersocialauth`.`user_id` = 42;

SELECT `films_film`.`id`, `films_film`.`status`, `films_film`.`created`, `films_film`.`updated`, 
`films_film`.`published`, `films_film`.`title_original`, `films_film`.`title_ru`, `films_film`.`slug`, 
`films_film`.`thumbnail`, `films_film`.`slogan`, `films_film`.`description`, 
`films_film`.`date_premiere`, `films_film`.`year_id`, `films_film`.`rating_votes`, 
`films_film`.`rating_score`, `films_film`.`rating_score_with_vote_weight`, `films_year`.`id`, 
`films_year`.`name`, `films_year`.`count`, `films_year`.`size` FROM `films_film` LEFT OUTER 
JOIN `films_year` ON (`films_film`.`year_id` = `films_year`.`id`) WHERE (`films_film`.`status` 
= 'published'  AND `films_year`.`id` IS NOT NULL) ORDER BY `films_film`.`published` DESC 
LIMIT 30;

...

Где они были вызваны вы не знаете, более того, это не только SQL-запросы из вьюх проекта, это так же запросы из команд, демонов каких-то, вообщем куча неизветсно откуда запросов. Как вам понять где эти запросы вызываются?

Нет проблем! Вы берете django-sql-stacktrace, запускаете свою локальную копию проекта (а на деле может пригодится и на продакшене) и увидите следующее:

...

SELECT COUNT(*) FROM `films_film` INNER JOIN `films_year` ON (`films_film`.`year_id` = `films_year`.`id`)
WHERE (`films_film`.`status` = 'published' AND `films_year`.`id` IS NOT NULL)
/* STACKTRACE: 
> File "/home/adw0rd/work/kinsburg_tv/kinsburg_tv/common/views.py", line 27, in get_context_data
> context = super(MainPage, self).get_context_data(**kwargs)

STACKTRACE: 
> File "/home/adw0rd/work/kinsburg_tv/kinsburg_tv/films/mixins.py", line 14, in get_context_data
> context = super(FilmsMixin, self).get_context_data(**kwargs)

STACKTRACE: 
> File "/home/adw0rd/work/kinsburg_tv/venv/local/lib/python2.7/site-packages/django/db/models/query.py", line 351, in count
> return self.query.get_count(using=self.db)

STACKTRACE: 
> File "/home/adw0rd/work/kinsburg_tv/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 418, in get_count
> number = obj.get_aggregation(using=using)[None]

STACKTRACE: 
> File "/home/adw0rd/work/kinsburg_tv/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py", line 384, in get_aggregation
> result = query.get_compiler(using).execute_sql(SINGLE)

STACKTRACE: 
> File "/home/adw0rd/work/kinsburg_tv/venv/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 818, in execute_sql
> cursor.execute(sql, params)

STACKTRACE: 
> File "/home/adw0rd/work/kinsburg_tv/venv/local/lib/python2.7/site-packages/sqlstacktrace/stacktracecursor.py", line 16, in execute
> stacks = get_stacktrace()

STACKTRACE: 
> File "/home/adw0rd/work/kinsburg_tv/venv/local/lib/python2.7/site-packages/sqlstacktrace/stacktrace.py", line 93, in get_stacktrace
> stack = get_stack()
*/;

...

Отличная работа! Теперь вы знаете откуда произошел вызов того или инного запроса, осталось только исправить эту проблему.

Установка и настройка

Вы можете установить с PyPI:

pip install django-sql-stacktrace

Или установить dev-версию с GitHub:

pip install -e git://github.com/adw0rd/django-sql-stacktrace.git#egg=sqlstacktrace

Теперь, добавьте в "INSTALLED_APPS":

INSTALLED_APPS = (
    ...
    'sqlstacktrace',
    ...
)

И включите SQL_STACKTRACE:

SQL_STACKTRACE = True

Получение исходного кода

Вы можете получить django-sql-stacktrace на https://github.com/adw0rd/django-sql-stacktrace. Это приложение распостраняется по лицензии BSD.

Комментарии

а может уже будешь делать на несколько языках? :)

Пока тренируюсь, завтра переведу скорее всего на русский...
Последующие статьи на английском буду сразу переводить на русский, а русские на английский вряд ли буду

а может уже будешь делать на несколько языках? :)

Готово!

Не работает для админки

Хм, надо посмотреть как для админки используется CursorWrapper

Не работает для админки

Я проверил, зашел в админку, смотрю в SQL-панель django-debug-toolbar и вижу трейсбек. Вы точно указали приложение в INSTALLED_APPS и указали SQL_STACKTRACE=True?

Оставьте свой комментарий

Markdown