Курс по Django: https://stepik.org/a/183363
Архив проекта: 36_sitewomen.zip
К этому моменту
мы с вами создали небольшой, но функциональный сайт с отображением статей, в
том числе по категориям и тегам. И, естественно, возникает вопрос, насколько
хорошо работает приложение нашего сайта? Здесь следует пояснить, что значит
«хорошо работает». В данном случае, я рассматриваю:
- скорость работы
приложения;
- нагрузку на СУБД
(частоту и сложность запросов);
- корректность
возвращаемых пользователю данных.
Чтобы
отслеживать эти и некоторые другие характеристики разрабатываемой программы, в Django имеется
довольно удобный инструмент под названием:
Django Debug Toolbar
Давайте
посмотрим, как его можно использовать для анализа работы нашего приложения.
Если перейти в
репозиторий pypi.org и в поиске
ввести «django debug toolbar», то увидим различные версии этого пакета.
Установим последнюю из них в виртуальное окружение. Для этого, в терминале
выполним команду:
pip
install django-debug-toolbar
После установки,
его нужно «прикрутить» к нашему сайту. Подробная информация о его настройки
доступна на странице:
https://django-debug-toolbar.readthedocs.io/en/latest/installation.html
Согласно этой
документации, в файле settings.py нужно
зарегистрировать это приложение, добавив в INSTALLED_APPS строчку:
INSTALLED_APPS = [
...
'debug_toolbar',
]
В этом же файле
в коллекции MIDDLEWARE нужно
прописать:
MIDDLEWARE = [
...
'debug_toolbar.middleware.DebugToolbarMiddleware',
]
Далее, в этом же
файле нужно прописать новую коллекцию INTERNAL_IPS со списком отслеживаемых IP-адресов
INTERNAL_IPS = [
'127.0.0.1',
]
Переходим в файл
urls.py пакета
конфигурации и добавляем следующий маршрут:
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('women.urls')),
path("__debug__/", include("debug_toolbar.urls")),
]
Все, инструмент
добавлен и давайте посмотрим, как он будет выглядеть и что показывать. Запускаем
тестовый веб-сервер, переходим на главную страницу сайта и справа отображается панель
Debug Toolbar.
Здесь мы видим
версию Django, время
формирования страницы, количество выполненных SQL-запросов,
список используемых шаблонов и так далее. В целом, это довольно удобный и
информативный инструмент. Если нужна более детальная информация, например, по SQL-запросам, то
достаточно кликнуть по этому пункту и появится развернутая информация. В
частности, здесь видим наши запросы, прописанные на уровне ORM-команд.
Разумеется, здесь мы их видим уже на уровне SQL-запросов к
конкретной СУБД (SQLite).
Уникальные
запросы нас вполне устраивают, они необходимы и не происходит дублирования. А
вот ниже видим однотипные запросы, что нехорошо. За что они отвечают. Смотрим
запрос и видим, что идет чтение названия рубрики. Очевидно, это связано с
обращением к категории в шаблоне index.html через
переменную p:
<p
class="first">Категория: {{p.cat.name}}</p>
Давайте
проверим, так ли это. Уберем временно эту строчку, обновим страницу, и
действительно, число запросов заметно уменьшилось, а скорость загрузки страницы
увеличилась. Почему это происходит? Вспоминаем, что в Django есть понятие «ленивых»
и «жадных» запросов. Ленивые, то есть, отложенные запросы, которые выполняются
только в момент непосредственного обращения к данным, например, для вывода
рубрики. Как раз здесь выполняется отложенный запрос. Они достаточно удобны при
работе с единичными записями, но когда их много, то возникает неприятный эффект
резкого увеличения числа SQL-запросов, что мы сейчас и наблюдаем.
Как можно
оптимизировать этот процесс? Очевидно, нужно сделать загрузку категорий и
постов одним запросом. Для этого в Django имеются два
полезных метода:
- select_related(key) – «жадная»
загрузка связанных данных по внешнему ключу key, который имеет
тип ForeignKey;
- prefetch_related(key) – «жадная»
загрузка связанных данных по внешнему ключу key, который имеет
тип ManyToManyField.
Как и где их
использовать. Смотрите, за главную страницу у нас отвечает функция
представления index() и в ней
происходит чтение опубликованных постов. Как раз здесь, после метода all() мы и запишем
метод select_related следующим образом:
def index(request):
data = {
'title': 'Главная страница',
'menu': menu,
'posts': Women.published.all().select_related('cat'),
'cat_selected': 0,
}
В этом методе
указываем атрибут cat, который определен во вторичной модели Women как ForeignKey для связки с
первичной моделью Category. Теперь, мы имеем «жадную» загрузку
дополнительных данных из таблицы category и для получения названия рубрики
нет необходимости делать запрос к БД.
Давайте
посмотрим, как это будет работать. Возвращаемся в браузер, обновляем главную
страницу и видим, что запросов действительно стало меньше. Вот так, благодаря Debug Toolbar и использованию
«жадного» запроса мы оптимизировали работу нашего сайта.
Аналогично
правим функции представления show_category() и show_tag_postlist() для
оптимизации при отображении списка статей по отдельным рубрикам.
Как видите, Debug Toolbar довольно
полезный инструмент для анализа работы сайта и я советую вам также использовать
его или какой-либо аналогичный, чтобы создавать оптимизированные сайты.
Курс по Django: https://stepik.org/a/183363