Files
2022_oknardia/CACHE_PRERENDER_SYSTEM.md

15 KiB
Raw Permalink Blame History

Система двухуровневого кеширования страниц серий

📖 Описание

Система страниц серий домов использует двухуровневое кеширование:

  1. Статический кеш — дорогостоящие данные (карты, графики, схемы), генерируются один раз и сохраняются на диск
  2. Динамические данные — верхняя статья (редактируется через админку) и таблица оконных проёмов (показывает свежие предложения), пересчитываются при каждом запросе

🏗️ Архитектура кеша

Для каждой серии создаются 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):

  1. View catalog_seria_info() обнаруживает отсутствие кеш-файлов
  2. Вычисляются дорогостоящие данные:
    • Геокоординаты всех зданий серии
    • Год ввода в эксплуатацию (для графика)
    • Схемы открывания окон
  3. Генерируются 3 отдельных файла в oknardia/templates/seria_info/prepared/
  4. Верхняя статья и таблица окон рендерятся из БД при каждом запросе
  5. Контекст получает пути к 3 кеш-файлам + свежие динамические данные
  6. Main-шаблон включает 3 кеш-файла + 2 динамических блока
  7. Ответ отправляется пользователю

При последующих запросах (cache hit):

  1. View обнаруживает, что все 3 файла существуют
  2. Верхняя статья пересчитывается заново из БД (от админа)
  3. Таблица окон пересчитывается заново (новые предложения видны сразу)
  4. Main-шаблон включает 3 статических файла + 2 динамических блока
  5. Ответ отправляется быстро (схемы, график, геоданные из кеша)

Ключевой мюмент: Всё свежее!

  • Кеширование не трогает верхнюю статью и таблицу окон → они всегда свежие
  • Новые цены от поставщиков видны пользователям сразу
  • Админ может редактировать текст про серию → видно без перезагрузки контейнера
  • Таблица пересчитывается в запросе через 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