Автор решил освоить серверный рендеринг сайтов в духе 2010-х — с SQL-базой и генерацией HTML на бэкенде. Раньше она уверенно собирала статические сайты, одностраничники на Vue.js с Lambda или Go-бэкендом, но для проекта с кучей разных страниц фронтенд-подход уже не радовал. Захотелось держать всю логику в одном месте, и Django внезапно оказался куда дружелюбнее, чем попытки взять Go standard library или Flask.
Первое, от чего автор в восторге, — кастомные query sets. Она определила класс EventQuerySet с методами вроде approved(), future() или with_tags(), которые навешивают нужные WHERE-условия. В коде представлений это превращается в цепочки Events.objects.approved().for_tab(tab).with_festivals(...). Синтаксис определения фильтров не самый любимый, но пользоваться получившимися методами — сплошное удовольствие и очень читаемо. Раньше автор думала «я знаю SQL, зачем query builder», а теперь заинтересовалась библиотеками-построителями запросов.
В шаблонах Django обнаружилась россыпь удобных фильтров: urlize превращает голые ссылки в кликабельные, linebreaksbr расставляет <br>, date форматирует даты. Но настоящая любовь — фильтр querystring. Ссылка {% querystring date=nav.prev_date %} меняет только один параметр в URL и не трогает остальные, а {% querystring outdoors=None %} убирает параметр совсем — идеально для фильтров на сайте.
Авто-миграции тоже вызывают тёплые чувства. Изменил модель — Django сам генерирует миграцию. За время работы набралось уже 19 штук, и возможность легко перекраивать базу по мере понимания задачи ощущается как огромное преимущество.
С классовыми представлениями и наследованием отношения не сложились. Автор попробовала вынести общий код в родительский класс для четырёх похожих вьюх, но быстро отказалась и переписала всё на функциях — получилось прямолинейнее и понятнее. Наследование ради интерфейсов самого Django (скажем, class EventQuerySet(SearchableQuerySetMixin, models.QuerySet)) вопросов не вызывает, но своё наследование для переиспользования кода она больше трогать не хочет.
Когда LLM-скраперы обнаружили сайт и начали слать по 10 запросов в секунду, автор заблокировала их и задумалась о производительности. На дешёвой VPS (~$10/мес) лёгкий нагрузочный тест ab -n 1000 -c 1 показал жалкие 2–3 запроса в секунду. Профилировщик py-spy показал, что Django много времени тратит на рендеринг шаблонов. Оказалось, автор случайно отключила cached template loader (он должен быть включён по умолчанию), пока копалась в файле настроек. После включения кеширования сайт легко выдаёт около 12 запросов в секунду, не загружая CPU целиком, — без скрупулёзных бенчмарков понятно, что разница огромна. Любопытно, что узким местом стали шаблоны, а не медленные запросы к базе; с SQLite проблемы с запросами всё равно проявились бы в CPU-профиле. Погружаться в глубокую оптимизацию автор пока не хочет, но обещает как-нибудь рассказать о Django ещё.