Отладчик Pycharm против проблемы 1+N
Tags: django
Published: 2020-09-07 08:15:18

## Лирика
К примеру, требуется вывести в API список пользователей, но не все данные, а только их `username`, и поэтому `queryset=User.objects.only('username')`. Допустим, что за один запрос выводится список из 20 пользователей. Теперь мы решили добавить поля `first_name` и `last_name` (в сериализатор, но не в queryset). Django Rest Framework перебирает все объекты по очереди. Не обнаружив в текущем объекте поля `first_name`, django делает запрос в БД за данными этого поля, потом повторяет то же самое для `last_name`. И так для каждого объекта. В результате имеем один запрос к БД для получения списка объектов и ещё 20 раз по 2 запроса. Итого 41 запрос.
В данном случае достаточно добавить недостающие поля в `only` или не использовать метод `only` вовсе. Даже тот, кто знает о коварстве метода `only`, может не знать об его участии в данном фрагменте кода. А всё потому, что подготовка queryset происходит во view, а использование в serializator. 
Описанный случай, является достаточно экзотичным, но хорошо показывает, как на пустом месте вместо одного запроса можно получить множество. Гораздо чаще приходится прописывать `prefetch_related` для борьбы с 1+N.

## Задействуем мощь отладчика Pycharm
Если при ручном тестировании своего кода мне нужно делать обращение к API, то я всегда включаю вывод логов отладчика, чтобы видеть обращение к БД. Я покажу как это делается, но перед этим вам нужно прочитать {% link gimntut/pycharm-2c1o %}
Прочитали? Тогда начинаем.
1. Откройте свой проект django и перейдите по ссылке `CursorDebugWrapper.execute` или `CursorDebugWrapper.debug_sql` если у вас `Django 3+`
2. Поставьте breakpoint на `logger.debug`
3. Сделайте правый клик на красном кружке
4. В появившимся диалоге отключите `Suspend`
5. Включите `Evalute and log` и напишите `'(%.3f) %s; args=%s'%(duration, sql, params)`

Должно получится так:

![Screenshot of Pycharm](https://dev-to-uploads.s3.amazonaws.com/i/qy63aguyxasyb11bzflg.png)

Теперь, если вы запустите проект под отладчиком, то увидите в консоли все запросы к БД и время их выполнения. В моём проекте запросов в БД от вызова одного API не очень много и 1+N сразу бросается в глаза, если не включен cacheops. Отключайте cacheops на машине разработки, тогда неправильные запросы к БД вы будете буквально чувствовать на собственной шкуре без всякого логирования и не допустите плохой код в проект.
Главная прелесть логирования через отладчик в том, что не требуется вносить изменения в код, и не придётся убирать за собой забытые print'ы. При этом я не удаляю breakpoint, когда он мне не нужен, а просто выключаю (<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>F8</kbd>). А когда становится нужен, снова включаю. Т.е. настроив breakpoint один раз, пользуюсь им всё время.

Но нужно знать 2 вещи. Во-первых, без отладчика эта история не работает. Во-вторых, даже с отладчиком эта история не работает, если у вас mssql aka SQL Server.

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