15 KiB
Система двухуровневого кеширования страниц серий
📖 Описание
Система страниц серий домов использует двухуровневое кеширование:
- Статический кеш — дорогостоящие данные (карты, графики, схемы), генерируются один раз и сохраняются на диск
- Динамические данные — верхняя статья (редактируется через админку) и таблица оконных проёмов (показывает свежие предложения), пересчитываются при каждом запросе
🏗️ Архитектура кеша
Для каждой серии создаются 3 отдельных кешируемых файла:
| Файл | Содержимое | Размер | Где появляется |
|---|---|---|---|
{seria_id}_id_static_flaps.html |
Схемы открывания и типовые размеры окон | 4-7KB | В разделе "Дома серии: типовые размеры" |
{seria_id}_id_static_graph.html |
Google Charts: график ввода в эксплуатацию | 2-3KB | В контейнере height:300px |
{seria_id}_id_static_map_stats.html |
Yandex Maps + блок статистики | 6-46KB | Карта (col-md-7) + статистика (col-md-4) |
Верхняя статья — ДИНАМИЧЕСКИЕ ДАННЫЕ, не кешируется!
Верхняя статья про серию (THIS_SERIA_DESCRIPTION) — это динамические данные, которые:
- Хранятся в БД (поле
sDescriptionмоделиSeria_Info) - Редактируются через админку → нужны изменения без перезагрузки контейнера
- Рендерятся всегда из БД, не сохраняются в кеш-файлы
Если бы мы кешировали верхнюю статью:
- Админ редактирует статью → кеш-файл не обновляется автоматически
- Нужно перезагрузить контейнер или вручную удалять файл кеша
- При регенерации кеша может произойти перезапись старыми данными
Решение: верхняя статья всегда рендерится из БД, как и таблица окон.
🔄 Логика работы
При первом запросе seriesId (cache miss):
- View
catalog_seria_info()обнаруживает отсутствие кеш-файлов - Вычисляются дорогостоящие данные:
- Геокоординаты всех зданий серии
- Год ввода в эксплуатацию (для графика)
- Схемы открывания окон
- Генерируются 3 отдельных файла в
oknardia/templates/seria_info/prepared/ - Верхняя статья и таблица окон рендерятся из БД при каждом запросе
- Контекст получает пути к 3 кеш-файлам + свежие динамические данные
- Main-шаблон включает 3 кеш-файла + 2 динамических блока
- Ответ отправляется пользователю
При последующих запросах (cache hit):
- View обнаруживает, что все 3 файла существуют
- Верхняя статья пересчитывается заново из БД (от админа)
- Таблица окон пересчитывается заново (новые предложения видны сразу)
- Main-шаблон включает 3 статических файла + 2 динамических блока
- Ответ отправляется быстро (схемы, график, геоданные из кеша)
Ключевой мюмент: Всё свежее!
- Кеширование не трогает верхнюю статью и таблицу окон → они всегда свежие
- Новые цены от поставщиков видны пользователям сразу
- Админ может редактировать текст про серию → видно без перезагрузки контейнера
- Таблица пересчитывается в запросе через Q-фильтры к БД (есть индексы на БД)
📁 Структура файлов
Templates (шаблоны)
oknardia/templates/seria_info/
├── all_seria_info_pre_light.html # Main-шаблон (включает 3 static-файла + динамику)
├── all_seria_info_pre_light_static_flaps.html # ШАГ 1: Схемы открывания (кешируется)
├── all_seria_info_pre_light_static_graph.html # ШАГ 2: График ввода (кешируется)
├── all_seria_info_pre_light_static_map_stats.html # ШАГ 3: Карта + статистика (кешируется)
└── prepared/ # Директория с кеш-файлами
├── 210_id_static_flaps.html
├── 210_id_static_graph.html
├── 210_id_static_map_stats.html
├── 100_id_static_flaps.html
└── ... (93 файла: 31 серия × 3 типа)
Генерация кеша (Web-логика)
oknardia/web/
├── catalog_series.py # catalog_seria_info() — генерирует 3 файла + динамику
└── management/commands/
└── regenerate_seria_prerender.py # Batch-команда для регенерации всех серий
🚀 Управление кешем
Разработка (DEV-режим)
python manage.py runserver
В DEV-режиме (DEBUG = True):
- Кеш не используется (всегда
PRE_RENDERED_STATIC_*_PATH = "") - Main-шаблон рендерит данные напрямую
- Удобно для разработки (вижу изменения сразу)
Production (PROD-режим)
Первоначальная генерация (все 31 серия):
python manage.py regenerate_seria_prerender
Вывод:
OK seria 100: 3 кеш-файла созданы
OK seria 12: 3 кеш-файла созданы
...
Готово. Обработано: 31. Создано/пересоздано: 31 × 3 файла. Пропущено: 0.
Регенерация конкретной серии:
python manage.py regenerate_seria_prerender --seria-id 210
Dry-run (без создания файлов):
python manage.py regenerate_seria_prerender --dry-run
Force-переписать даже если есть кеш:
python manage.py regenerate_seria_prerender --force
📊 Когда нужна регенерация кеша?
✅ Регенерируйте, если:
- Изменены координаты зданий (geo-данные)
- Добавлены новые здания в серию
- Обновлены годы ввода в эксплуатацию (для графика)
- Изменены схемы открывания окон
- Обновлена верхняя статья про серию
# Все изменилось → перестроить все
python manage.py regenerate_seria_prerender --force
# Изменилась одна серия → перестроить одну
python manage.py regenerate_seria_prerender --seria-id 210
❌ НЕ нужна регенерация, если:
- Добавлены новые предложения (цены от поставщиков)
- Обновлены наличие/status существующих предложений
- Система просто должна показать свежие цены
Таблица окон пересчитывается при каждом запросе автоматически! 🎉
🔌 Интеграция с Docker
В контейнере (PROD-режим):
# Генерируем кеш пр<D0BF><D180> запуске
RUN python manage.py regenerate_seria_prerender
# Запускаем сервер
CMD ["gunicorn", "oknardia.wsgi:application", "--bind", "0.0.0.0:8000"]
Кеш-файлы сохраняются на диск в томе, поэтому переживают перезагрузку контейнера.
📝 Контекстные переменные
При первом запросе (происходит генерация):
View catalog_seria_info() отправляет в шаблон:
to_template = {
"THIS_SERIA_ID": seria_id, # ID серии (210)
"THIS_SERIA_NAME": q_seria.sName, # Название ("1-335")
"THIS_SERIA_DESCRIPTION": html_description, # Верхняя статья
"FLAP_DIM": flap_dimensions, # Массив схем открывания
"DATA4GRAPH": graph_data, # Годы и кол-во домов
"DATA4GEO": geo_data, # Координаты зданий
"ACCOUNTS": buildings_count, # Кол-во квартир
"APARTMENTS": families_count, # Кол-во семей
"RESIDENTIAL_M2": total_area, # Площадь жилая
# ... и другие
}
Для шаблонов генерации кеша:
Каждый template файл получает все эти переменные и рендерится отдельно.
Для main-шаблона:
Main-шаблон получает пути только к 3 кеш-файлам:
to_template.update({
"PRE_RENDERED_STATIC_FLAPS_PATH": "seria_info/prepared/210_id_static_flaps.html",
"PRE_RENDERED_STATIC_GRAPH_PATH": "seria_info/prepared/210_id_static_graph.html",
"PRE_RENDERED_STATIC_MAP_STATS_PATH": "seria_info/prepared/210_id_static_map_stats.html",
})
# Верхняя статья всегда передается как THIS_SERIA_DESCRIPTION и рендерится динамически
to_template.update({
"THIS_SERIA_DESCRIPTION": html_description, # Из БД, не кешируется
})
Main-шаблон использует {% include %} для 3 кеш-файлов, а верхнюю статью рендерит напрямую: {{ THIS_SERIA_DESCRIPTION|safe }}.
🎯 Примеры использования
Добавили новое здание в серию 210
# Обновили БД через Django ORM/admin
python manage.py shell
>>> from oknardia.models import Building_Info
>>> Building_Info.objects.create(...)
# Регенерируем кеш только этой серии
python manage.py regenerate_seria_prerender --seria-id 210
# Пользователи видят новое здание на карте и в таблице
Обновили года ввода в эксплуатацию
# Изменили данные
python manage.py shell
>>> from oknardia.models import Building_Info
>>> Building_Info.objects.filter(...).update(...)
# Кеш станет невалидным — нужна регенерация
python manage.py regenerate_seria_prerender --force
# Пользователи видят обновленный график
Добавили новое предложение (цену)
# PriceOffer.objects.create(...) → система добавляет новое предложение
# НЕ нужна регенерация!
# Таблица окон обновилась сама на следующем запросе
# Пользователи видят новое предложение сразу
🐛 Отладка
Проверить, какие кеш-файлы существуют:
ls -lah oknardia/templates/seria_info/prepared/
Вручную удалить кеш (для тестирования):
# Удалить кеш одной серии
rm oknardia/templates/seria_info/prepared/210*.html
# Удалить ВСЕ кеш-файлы
rm oknardia/templates/seria_info/prepared/*_id_static_*.html
Проверить содержимое кеш-файла:
cat oknardia/templates/seria_info/prepared/210_id_static_graph.html | head -20
cat oknardia/templates/seria_info/prepared/210_id_static_flaps.html | head -30
cat oknardia/templates/seria_info/prepared/210_id_static_map_stats.html | head -50
Логирование:
В catalog_series.py логируем создание файлов:
logger.info(f"Cache created: {file_flaps}")
logger.info(f"Cache created: {file_graph}")
logger.info(f"Cache created: {file_map_stats}")
# file_upper НЕ создается — верхняя статья рендерится динамически
📈 Производительность
Без кеша (DEV-режим):
- ~2-3 сек на запрос (вычисляются geo, graph, flaps)
- Каждый запрос трогает БД
- Удобно для разработки
С кешем (PROD-режим):
- ~100-300 мс на первый запрос (генерируется кеш)
- ~50-100 мс на последующие (включаются файлы + динамическая таблица)
- Статические данные из кеша (очень быстро)
- Таблица окон кешируется на уровне DB-запроса (индексы работают)
✅ Чек-лист для администратора
При развертывании в production:
- Запустить
python manage.py regenerate_seria_prerender(сгенерировать все 93 файла) - Проверить размеры файлов в
prepared/(~100-200 KB всего) - Протестировать на локалхосте
DEBUG = False - Проверить, что таблица окон обновляется при добавлении новых предложений
- Настроить логирование создания кеша в продакшене
🔗 Близкие компоненты
- Main-шаблон:
oknardia/templates/seria_info/all_seria_info_pre_light.html - Динамическая таблица:
oknardia/templates/seria_info/all_seria_info_pre_light_dynamic_include.html - View:
oknardia/web/catalog_series.py::catalog_seria_info() - Management-команда:
oknardia/web/management/commands/regenerate_seria_prerender.py - Тесты:
oknardia/web/test_prices.py(проверяет свежесть таблицы)
Версия: 2.0 (Двухуровневое кеширование)
Последнее обновление: 2026-05-19
Статус: ✅ Production-ready