44 KiB
MANAGEMENT_RUNBOOK.md
Единый runbook по management-командам проекта.
Документ отвечает на 3 вопроса:
- что запускать;
- когда запускать;
- как безопасно откатываться/повторять запуск.
Каталог команд
regenerate_seria_roots— пересчет корневых серий (иерархия и консолидация).generate_sitemaps— оффлайн генерация sitemap-файлов.regenerate_seria_prerender— оффлайн пересборка pre-render шаблонов дляcatalog_seria_info.populate_seo_fields— автозаполнение SEO-полей блога из существующих данных.make_rating— пересчёт рейтингов профилей и стеклопакетов методом Манна-Уитни.
Общие правила запуска
- Запускать команды из корня репозитория.
- Для локального/CI запуска использовать
poetry. - Не запускать тяжелые операции через HTTP-эндпоинты
/service/*. - Перезапуск веб-сервера (
gunicorn/uWSGI) делать отдельным шагом оркестрации, а не из кода Django.
Базовый шаблон запуска:
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py <command> [args]
1) Команда regenerate_seria_roots
Назначение:
- пересчитать корневые серии (root) для всей иерархии серий домов.
- консолидировать различные написания одной и той же серии в одну "корневую" серию.
Контекст
На разных источниках данные о типовых сериях домов были записаны с разными орфографическими вариантами. Например серия II-57 могла быть обозначена как:
2-57(цифра вместо кириллицы)И-57(кириллица И вместо латинской II)П-57(опечатка)- и т.п.
При парсинге данных эти варианты могли оказаться в БД как отдельные серии, хотя на самом деле это одна и та же серия.
Функция regenerate_seria_roots связывает все эти варианты (алиасы) с одной корневой серией.
Когда это нужно
При добавлении новых адресов и серий типового строительства, при ручном редактировании иерархии серий в админке,
при загрузке новых данных с разными орфографическими вариантами серий. Кроме того, если для уже существующих в базе
серий будут получены данные о типовых размерах оконных проёмов и типов квартирах (сейчас в базе около 4500 серий, из
них всего 31 корневых серий и 1957 серий с найденным корнем... ещё 2502 неописанных серии без корня, т.е. больше
половины, могут пополнить каталог Окнардии.
Как это работает
-
Этап 1: Находит "корневые" серии (root series) — те, что реально используются в таблице
Apartment_Type(т.е. у которых есть квартиры). Для каждой такой серии устанавливаетkRoot_id = own_id. -
Этап 2: Для всех остальных серий:
- Движется вверх по дереву иерархии (
kParent_id) - Ищет корневую серию (ту, которая либо не имеет родителя, либо она в списке корневых)
- Устанавливает найденную корневую серию в поле
kRoot_id - Если не находит корневую серию →
kRoot_id = None
- Движется вверх по дереву иерархии (
Пример структуры после обработки
Таблица: Seria_Info
id | sSeriaName | kParent_id | kRoot_id | Комментарий
----|------------|------------|-----------|-------------------
123 | II-57 | NULL | 123 | Корневая серия
124 | 2-57 | 123 | 123 | Алиас (через родителя)
125 | И-57 | 123 | 123 | Алиас (через родителя)
126 | П-57 | 123 | 123 | Алиас (через родителя)
Базовый запуск
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_roots
Параметры запуска
--verbosity 0 — только ошибки (минимум информации):
poetry run python oknardia/manage.py regenerate_seria_roots --verbosity 0
--verbosity 1 — точки/плюсы (стандартный режим):
poetry run python oknardia/manage.py regenerate_seria_roots
# или явно
poetry run python oknardia/manage.py regenerate_seria_roots --verbosity 1
--verbosity 2 — подробный вывод (названия серий):
poetry run python oknardia/manage.py regenerate_seria_roots --verbosity 2
--verbosity 3 — очень подробный вывод в виде таблицы:
poetry run python oknardia/manage.py regenerate_seria_roots --verbosity 3
Примеры вывода
Verbosity 0 (только ошибки - чистый вывод):
✅ Пересчет завершен! Время: 2.18с
Verbosity 1 (магический режим - точки и символы):
=== ПЕРЕСЧЕТ КОРНЕВЫХ СЕРИЙ ===
Этап 1: Ищем корневые серии в таблице квартир...
✓ Найдено корневых серий: 241
...............................
Этап 2: Главная магия - обрабатываем все серии в иерархии...
-----++..--.++--...--.+.++++.-+++++++-.-.++.-+--++--++++-+++++++-++.+--.+++-+-..++++++-++++++++++--.-++++++-++++
+--+-+++++++++-++++++++++-++++--+++.+++--+++++++++++++++++++---++.+-+-+++++-++++++++++-+++-+----+.-+++-+--++++++
+++----+--+-+++++-+--+++--+++-.+++++-++++++++-+---++-+++++---+++------++----++-+--++----+--++--++++--+++++++++++
+++++++-------++++---+++-[... очень много символов ...]
=== РЕЗУЛЬТАТЫ ===
✓ Корневых серий (обработаны на этапе 1): 31
✓ Серий с найденным корнем: 1957
⚠ Серий без корня: 2502
✅ Пересчет завершен! Время: 2.18с
Легенда магического режима:
.= корневая серия (обработана на этапе 1)+= серия с найденным корнем-= серия без найденного корняE= ошибка при обработке
Verbosity 2 (подробный):
=== ПЕРЕСЧЕТ КОРНЕВЫХ СЕРИЙ ===
Этап 1: Ищем корневые серии в таблице квартир...
✓ Найдено корневых серий: 241
✓ 0008 П-44
✓ 0009 П-3
✓ 0012 II-49
✓ 0017 КОПЭ
...
Этап 2: Главная магия - обрабатываем все серии в иерархии...
0001: Нет корня
0002: Нет корня
0006: корень → 12
0007: корень → 9
0008: корневая
...
Verbosity 3 (очень подробный - таблица):
=== ПЕРЕСЧЕТ КОРНЕВЫХ СЕРИЙ ===
Этап 1: Ищем корневые серии в таблице квартир...
✓ Найдено корневых серий: 241
✓ 0008 | П-44 | корневая
✓ 0009 | П-3 | корневая
✓ 0012 | II-49 | корневая
...
Этап 2: Главная магия - обрабатываем все серии в иерархии...
--------------------------------------------------------------------------------------------------------------
ID | Название | Родитель | Путь | Результат
--------------------------------------------------------------------------------------------------------------
...
...
2565 | Г-ЗИ | 9 | 9 | ✓ Корень #9
2566 | I-528КП-809/69 | - | (нет) | ✗ Нет корня
2567 | 464Д-0154 | 3339 | 3339 → 963 → 375 | ✓ Корень #375
2568 | УЛГ-507-4/64 | 2105 | 2105 | ✓ Корень #2105
2569 | ЛГ-507-4 | 2105 | 2105 | ✓ Корень #2105
2570 | 1ЛГ-600-И-1 | - | (нет) | ✗ Нет корня
2571 | 464Д-0154 Новополоцкого ДСК | 3339 | 3339 → 963 → 375 | ✓ Корень #375
2572 | 121-0142,13,87 | - | (нет) | ✗ Нет корня
...
...
--------------------------------------------------------------------------------------------------------------
=== РЕЗУЛЬТАТЫ ===
✓ Корневых серий (обработаны на этапе 1): 31
✓ Серий с найденным корнем: 1957
⚠ Серий без корня: 2502
✅ Пересчет завершен! Время: 2.18с
Когда запускать
- После первого развертывания — консолидировать иерархию серий.
- После ручного редактирования иерархии (добавления родитель-потомков в админку).
- После загрузки новых данных с разными орфографическими вариантами серий.
- По расписанию (опционально, например раз в месяц):
0 2 * * 1 cd /home/user/app-path/2022-oknardia && poetry run python oknardia/manage.py regenerate_seria_roots >> /var/log/oknardia-seria-roots.log 2>&1
Откат и безопасность
- Безопасна для повторного запуска — просто пересчитывает все
kRoot_id. - Откат через SQL — если нужно очистить поле (перед запуском рекомендуется бэкап):
UPDATE oknardia_seria_info SET kRoot_id = NULL; - Проверка результатов — после запуска можно проверить:
poetry run python oknardia/manage.py shell -c " from oknardia.models import Seria_Info count_null = Seria_Info.objects.filter(kRoot_id__isnull=True).count() count_with_root = Seria_Info.objects.filter(kRoot_id__isnull=False).count() print(f'Серий без корня: {count_null}') print(f'Серий с корнем: {count_with_root}') "
2) Команда generate_sitemaps
Назначение:
- пересобрать
sitemap.xmlи chunk-файлы вMEDIA_ROOT/_serv_sitemap.
Базовый запуск:
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py generate_sitemaps
Запуск с параметрами:
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py generate_sitemaps \
--compare-min-depth 2 \
--compare-max-depth 4 \
--max-items 40000 \
--max-file-size 5242880 \
--max-files-qty 998
Когда запускать:
- после деплоя;
- по расписанию (cron/systemd timer);
- после крупных изменений данных каталога/блога.
Важные замечания
Чтобы sitemap.xml отдавал прокси-nginx напрямую из файловой системы, нужно, чтобы он физически лежал
в MEDIA_ROOT/_serv_sitemap/sitemap.xml.
Допустимо, что файл доступен по двум URL (корневой и media), но в robots.txt должен быть указан один
канонический вариант sitemap.xml
NGINX snippet (alias для корневого sitemap)
# Корневой sitemap.xml (для привычного для поисковиков URL)
location = /sitemap.xml {
alias /<путь-к-каталогку-с-докер-приложением>/media/_serv_sitemap/sitemap.xml;
default_type application/xml;
add_header Cache-Control "public, max-age=300";
}
3) Команда regenerate_seria_prerender
Назначение:
- пересобрать pre-render шаблоны для страниц серий (
catalog_seria_info) в каталогеseria_info/prepared/.
Проверка без записи файлов:
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_prerender --dry-run
Пересборка только отсутствующих файлов:
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_prerender
Принудительная пересборка всех root-серий:
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_prerender --force
Выборочная пересборка:
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_prerender --seria-id 843 --seria-id 2100 --force
Когда запускать:
- после обновления логики
catalog_seria_info; - после массового обновления данных серий/окон/квартир;
- после очистки
seria_info/prepared/.
4) Команда populate_seo_fields
Назначение:
- автозаполнить SEO-поля (
sSlug,sMetaDescription,sMetaKeywords) для всех существующих записей блога.
Используется:
- при первом развертывании новой версии с автогенерацией SEO-полей;
- при восстановлении из бэкапа где SEO-поля пусты;
- при изменении логики автогенерации (с флагом
--force).
Базовый запуск
Заполнить только пустые SEO-поля (стандартный вариант):
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py populate_seo_fields
Параметры запуска
--dry-run — только показать что будет сделано (без сохранения в БД):
poetry run python oknardia/manage.py populate_seo_fields --dry-run
--force — переполнить ВСЕ SEO-поля, даже уже заполненные:
poetry run python oknardia/manage.py populate_seo_fields --force
--clean — очистить все SEO-поля перед заполнением (для переделки):
poetry run python oknardia/manage.py populate_seo_fields --clean
Комбинация флагов — сухой прогон переполнения всех полей:
poetry run python oknardia/manage.py populate_seo_fields --dry-run --force
Что заполняется
| Поле | Источник | Результат |
|---|---|---|
sSlug |
sPostHeader |
URL-безопасный слаг (max 200 символов) |
sMetaDescription |
sPostContent |
Первые 160 символов (исключая теги <cut>) |
sMetaKeywords |
sPostHeader |
Заголовок + префикс "oknardia, окнардия, блог, публикация" (max 256 символов) |
Пример результата:
sPostHeader = "Профиль Brusbox Super Aero"
↓
sSlug = "profil-brusbox-super-aero"
sMetaDescription = "brusbox-super-aero-pyatikamernaya-profil-sistema..."
sMetaKeywords = "oknardia, окнардия, блог, публикация, Профиль Brusbox Super Aero"
Когда запускать
- После первого развертывания — заполнить SEO-поля всех 29 существующих постов одной командой.
- Один раз — команда идемпотентна (при повторном запуске не будет ничего менять, т.к. пустые поля остатся).
- При изменении логики — использовать
--clean --forceдля полной переделки всех SEO-полей.
Пример полного сценария
cd /Users/e-serg/PRJ/2022-oknardia
# Шаг 1: Проверить что будет заполнено
poetry run python oknardia/manage.py populate_seo_fields --dry-run
# Шаг 2: Если результат устраивает — запустить реально
poetry run python oknardia/manage.py populate_seo_fields
# Шаг 3: Проверить что заполнилось
poetry run python oknardia/manage.py shell -c "
from oknardia.models import BlogPosts
posts = BlogPosts.objects.all()
print(f'Пусто sSlug: {posts.filter(sSlug=\"\").count()}')
print(f'Пусто sMetaDescription: {posts.filter(sMetaDescription=\"\").count()}')
print(f'Пусто sMetaKeywords: {posts.filter(sMetaKeywords=\"\").count()}')
"
Возвращаемая информация
======================================================================
ИТОГОВЫЙ ОТЧЕТ
======================================================================
✓ sSlug заполнено: 28 раз
✓ sMetaDescription заполнено: 28 раз
✓ sMetaKeywords заполнено: 28 раз
✓ Записей обновлено в БД: 28
✗ Ошибок при обработке: 0
✅ Обновлено 28 записей успешно!
Откат и безопасность
- ✅ Безопасна для повторного запуска — пустые поля не изменяются при повторной работе.
- ✅ Откат через SQL — если нужно очистить, используй:
UPDATE oknardia_blogposts SET sSlug='', sMetaDescription='', sMetaKeywords=''; - ✅ Всегда используй
--dry-runперед первым запуском для проверки.
5) Команда make_rating
Назначение:
- пересчитать рейтинги оконных профилей, стеклопакетов и наборов услуг используя адаптированный метод Манна-Уитни (Mann-Whitney U Step Rank).
- сохранить результаты в поля
fProfileRating,fGlazingRating,fSetRating(0.0 … 5.0 звёзд). - заполнить JSON-состав рейтинга (детальный разбор по каждому параметру) в поля
sProfileDescription,sGlazingDescription,sSetDescription. - алгоритм рассчитывает три этапа ранжирования: профили → стеклопакеты → наборы (которые зависят от профилей и стеклопакетов).
Базовый запуск
Пересчитать рейтинги всех профилей и стеклопакетов (стандартный режим):
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py make_rating
Параметры запуска
--verbosity 0 — минимум информации (только ошибки):
--verbosity 1 — стандартная информация (по умолчанию):
--verbosity 3 — очень подробный вывод (для отладки, для каждого профиля/стеклопакета таблица):
Пример использования с параметром --verbosity:
poetry run python oknardia/manage.py make_rating --verbosity 3 | head -500
АЛГОРИТМ: Метод Манна-Уитни (Mann-Whitney U Step Rank)
Команда использует адаптированный вариант критерия Манна-Уитни для ранжирования параметров качества оконных предложений и комопнентов (профилей, стеклопакетов, наборов услуг) на основе их технических характеристик и популярности у поставщиков.
Как это работает:
-
Сортировка объектов по одному параметру (например, по теплопередаче):
- Профиль A: 0.60 Ro → ранг = 0.0
- Профиль B: 0.60 Ro → ранг = 0.0 (то же значение, ранг не меняется)
- Профиль C: 0.80 Ro → ранг = 1.0 (новое значение, добавляем вес параметра)
- Профиль D: 0.95 Ro → ранг = 2.0 (ещё новое значение)
-
Направление ранжирования определяется флагом
revers:revers=False— БОЛЬШЕ = ЛУЧШЕ (например, теплопередача, звукоизоляция)revers=True— МЕНЬШЕ = ЛУЧШЕ (например, высота в проёме для прочности)
-
Нормализация рангов к диапазону 0.0 … 1.0:
- Профиль A: 0.0 / 2.0 = 0.0
- Профиль B: 0.0 / 2.0 = 0.0
- Профиль C: 1.0 / 2.0 = 0.5
- Профиль D: 2.0 / 2.0 = 1.0
-
Суммирование рангов по всем параметрам:
- TmpRating = Σ(ранг_параметра × вес_параметра)
-
Преобразование в звёзды (0.0 … 5.0):
- ТmpRating нормализуется к 0..1
- Умножается на 5.0 для получения финального рейтинга
Пример итогового рейтинга профиля:
Профиль "Brusbox Super Aero"
Теплопередача: 0.60 Ro (ранг 0.9, вес 1.0)
Звукоизоляция: 33 дБ (ранг 0.8, вес 1.0)
Высота в проёме: 112 мм (ранг 0.6, вес 0.3)
Количество камер: 6 шт (ранг 0.7, вес 0.1)
Итого: (0.9×1.0 + 0.8×1.0 + 0.6×0.3 + 0.7×0.1) / 2.3 ≈ 3.8 звёзд ⭐⭐⭐⭐
ПРОФИЛИ: какие параметры учитываются
| № | Параметр | Поле БД | ЛУЧШЕ | Вес | Описание |
|---|---|---|---|---|---|
| 1 | Звукоизоляция | fProfileSoundproofing |
БОЛЬШЕ дБ | 1.0 | Сопротивление шуму (дБ) |
| 2 | Теплопередача | fProfileHeatTransf |
БОЛЬШЕ Ro | 1.0 | Сопротивление теплопередаче (м²×°C/Вт) |
| 3 | Высота в проёме | iProfileHeight |
МЕНЬШЕ мм | 0.3 | Видимая высота в световом проёме (экономия) |
| 4 | Высота фальца | iProfileRabbet |
БОЛЬШЕ мм | 0.2 | Глубина фальца для герметизации |
| 5 | Толщина стеклопакета | iProfileGlazingThickness |
БОЛЬШЕ мм | 0.2 | Максимальная толщина стеклопакета |
| 6 | Толщина профиля | iProfileThickness |
БОЛЬШЕ мм | 0.2 | Монтажная (боковая) ширина профиля |
| 7 | Контуры уплотнения | fProfileSeals |
БОЛЬШЕ контуров | 1.2 | Количество контуров уплотнения |
| 8 | Количество камер | iProfileCameras |
БОЛЬШЕ шт | 0.1 | Число камер в профиле (из рамки + створки) |
| 9 | Популярность | NumOffer |
БОЛЬШЕ предложений | 0.1 | Используется ли профиль в коммерческих предложениях |
Примеры интерпретации:
- Профиль с рейтингом 5.0 ⭐⭐⭐⭐⭐: отличная теплопередача + звукоизоляция + много камер + многоконтурные уплотнения.
- Профиль с рейтингом 2.0 ⭐⭐: среднее качество, слабые характеристики.
- Профиль с рейтингом 0.5 ⭐: слабые характеристики или производить не предоставил данных и их нет в отрытых источниках.
СТЕКЛОПАКЕТЫ: какие параметры учитываются
| № | Параметр | Поле БД | ЛУЧШЕ | Вес | Описание |
|---|---|---|---|---|---|
| 1 | Звукоизоляция | fGlazingSoundproofing |
БОЛЬШЕ дБ | 1.0 | Звукоизоляционный коэффициент (дБ) |
| 2 | Теплопередача | fGlazingHeatTransfer |
БОЛЬШЕ Ro | 1.0 | Сопротивление теплопередаче (м²×°C/Вт) |
| 3 | Светопропускание | fGlazingLightTransmission |
БОЛЬШЕ % | 0.25 | Коэффициент пропускания видимого света (%), отражение света снаружи |
| 4 | Солнцепропускание | fGlazingPassingSun |
МЕНЬШЕ % | 0.15 | Коэффициент солнечного излучения (SHGC) — В России меньше = лучше для охлаждения летом |
| 5 | Толщина | iGlazingThickness |
БОЛЬШЕ мм | 0.1 | Общая толщина стеклопакета |
| 6 | Количество камер | iGlazingCamerasN |
БОЛЬШЕ шт | 0.1 | Число воздушных/аргоновых камер |
Особенности стеклопакетов:
- Светопропускание = как много естественного света проходит в помещение (больше = лучше)
- Солнцепропускание = как много солнечного тепла/излучения проходит (в России: меньше = лучше, потому что внутри есть отражающее напыление)
- Двухкамерный (с аргоном) почти всегда лучше однокамерного
- Трёхкамерные = премиум для холодного климата
Примеры интерпретации:
- 5.0 ⭐⭐⭐⭐⭐: трёхкамерный с хорошей теплопередачей, звукоизоляцией (обычно с аргоном и напылением).
- 3.0 ⭐⭐⭐: двухкамерный, среднее качество
- 1.0 ⭐: однокамерный старого образца или с плохими характеристиками
НАБОРЫ: какие параметры учитываются
| № | Параметр | Поле БД | ЛУЧШЕ | Вес | Описание |
|---|---|---|---|---|---|
| 1 | Актуальность | dModify |
МЕНЬШЕ (свежее) | 0.3 | Дата последнего обновления (timestamp) |
| 2 | Доставка | bSetDelivery |
ДА (1) | 0.8 | Включена ли доставка в стоимость |
| 3 | Монтаж/демонтаж | bSetUninstallInstall |
ДА (1) | 1.0 | Включены ли услуги монтажа и демонтажа |
| 4 | Подоконник | sSetSill |
ДА (1) | 0.5 | Включен ли подоконник |
| 5 | Водоотлив | sSetPanes |
ДА (1) | 0.8 | Включен ли водоотлив/козырёк |
| 6 | Откос | sSetSlope |
ДА (1) | 0.5 | Включены ли откосы |
| 7 | Климат-контроль | sSetClimateControl |
ДА (1) | 0.3 | Включено ли управление микроклиматом |
| 8 | Число предложений | NumOffer |
БОЛЬШЕ | 0.2 | Популярность набора (кол-во активных предложений) |
| 9 | Гибкость скидок | iDiscountVariantsCount |
БОЛЬШЕ вариантов | 0.5 | Кол-во вариантов скидок из формулы офиса |
| 10 | Размер скидок | fDiscountMax |
БОЛЬШЕ % | 1.0 | Максимальная скидка из всех вариантов |
ВАЖНО: Итоговый рейтинг набора состоит из трёх компонентов:
- Рейтинг параметров услуг (Актуальность, Доставка, Монтаж, Подоконник и т.д.)
- Рейтинг входящего стеклопакета (ранжируется отдельно)
- Рейтинг входящего профиля (ранжируется отдельно)
Формула итогового рейтинга набора (fSetRating):
k1 = нормализованный TmpRating (услуги) * вес услуг
k2 = нормализованный рейтинг стеклопакета * RARING_WEIGHT_GLAZING_IN_SET (обычно 1.5)
k3 = нормализованный рейтинг профиля * RARING_WEIGHT_PVC_PROFILE_IN_SET (обычно 1.5)
fSetRating = k1 + k2 + k3 (итого от 0.0 до 5.0 звёзд)
Примеры интерпретации:
- 5.0 ⭐⭐⭐⭐⭐: набор с премиум компонентами (хороший профиль и стеклопакет) + полный пакет услуг (доставка, монтаж, подоконник, откос, климат-контроль) + значительные скидки.
- 3.5 ⭐⭐⭐⭐: хороший профиль/стеклопакет + базовые услуги (доставка, монтаж) + скромные скидки.
- 2.0 ⭐⭐: эконом компоненты или слабые услуги (нет доставки, нет откосов).
- 1.0 ⭐: минимальный пакет или устаревшие предложения (давно не обновлялись).
Когда запускать
-
После первого развертывания — заполнить рейтинги всех профилей, стеклопакетов и наборов.
-
После изменения каталога (добавление нового профиля/стеклопакета/набора).
-
После уточнения характеристик (например, поставщик предоставил новые данные).
poetry run python oknardia/manage.py make_rating -
По расписанию (например, ежемесячно, чтобы пересчитать популярность):
30 2 * * 1 cd /home/user/app-path/2022-oknardia && poetry run python oknardia/manage.py make_rating >> /var/log/oknardia-rating.log 2>&1 -
После обновления весов в
settings.py(константыRANK_PVCP_*,RANK_GLAZ_*).
Откат и безопасность
- Безопасна для повторного запуска — пересчитывает все рейтинги заново.
- Всегда обновляет только рейтинги — другие данные в таблицах не меняются.
- Откат через SQL — если нужно установить нулевые значения (перед запуском рекомендуется бэкап базы):
-- Очистить рейтинги профилей UPDATE oknardia_pvcprofiles SET fProfileRating = 0.0, sProfileDescription = '{}'; -- Очистить рейтинги стеклопакетов UPDATE oknardia_glazing SET fGlazingRating = 0.0, sGlazingDescription = '{}'; -- Очистить рейтинги наборов UPDATE oknardia_setkit SET fSetRating = 0.0, sSetDescription = '{}';
Примеры из реальных данных
Пример вывода --verbosity 1:
=== НАЧАЛИ ПЕРЕСЧЁТ РЕЙТИНГОВ ===
========================================
[ЭТАП 1]: Пересчёт рейтингов ПРОФИЛЕЙ...
========================================
✓ Обнулены рейтинги у 94 профилей
✓ Найдено 94 профилей для ранжирования
✓ Сохранено 94 профилей с финальными рейтингами
=============================================
[ЭТАП 2]: Пересчёт рейтингов СТЕКЛОПАКЕТОВ...
=============================================
✓ Обнулены рейтинги у 97 стеклопакетов
✓ Найдено 97 стеклопакетов для ранжирования
✓ Сохранено 97 стеклопакетов с финальными рейтингами
================================================
[ЭТАП 3]: Пересчёт рейтингов НАБОРОВ (SetKit)...
================================================
✓ Обнулены рейтинги у 27 наборов
✓ Найдено 27 наборов для ранжирования
✓ Сохранено 27 наборов с финальными рейтингами
[OK!] ПЕРЕСЧЁТ РЕЙТИНГОВ ЗАВЕРШЁН УСПЕШНО!
• Обновлено профилей: 94
• Обновлено стеклопакетов: 97
• Обновлено наборов: 27
Пример вывода --verbosity 3 (наиболее подробный):
=== НАЧАЛИ ПЕРЕСЧЁТ РЕЙТИНГОВ ===
========================================
[ЭТАП 1]: Пересчёт рейтингов ПРОФИЛЕЙ...
========================================
✓ Обнулены рейтинги у 94 профилей
✓ Найдено 94 профилей для ранжирования
...
...
====================================================================================================
ПРОФИЛЬ: politech W80 (ID: 78)
====================================================================================================
Характеристика Значение Ранг (0..1) Вклад
----------------------------------------------------------------------------------------------------
Высота в проёме 120 мм 0.368 *
Популярность 0 предл. 0.000
Теплопередача 0.91 Ro 0.657 ***
Толщина профиля 80 мм 0.588 **
Толщина стеклопакета 42 мм 0.409 **
Уплотнители 3 контуров 1.000 *****
Фальц 14 мм 0.150
Число камер 12 шт 0.714 ***
Шумоизоляция 44.00 дБ 0.909 ****
----------------------------------------------------------------------------------------------------
ИТОГО: Рейтинг = 4.94/5.0 ****
...
...
✓ Сохранено 94 профилей с финальными рейтингами
=============================================
[ЭТАП 2]: Пересчёт рейтингов СТЕКЛОПАКЕТОВ...
=============================================
✓ Обнулены рейтинги у 97 стеклопакетов
✓ Найдено 97 стеклопакетов для ранжирования
...
...
====================================================================================================
СТЕКЛОПАКЕТ: Однокамерный 5-4, 25 мм (И+аргон) (ID: 60) | Марка:СПО 5М1-Ar16-И4
====================================================================================================
Характеристика Значение Ранг (0..1) Вклад
----------------------------------------------------------------------------------------------------
Камеры — 0.000
Светопропускание 74.00% 0.824 ****
Солнцепропускание 58.00% 0.450 **
Теплопередача 0.91 Ro 0.936 ****
Толщина 25 мм 0.400 **
Шумоизоляция — 0.429 **
----------------------------------------------------------------------------------------------------
ИТОГО: Рейтинг = 4.87/5.0 ****
...
...
✓ Сохранено 97 стеклопакетов с финальными рейтингами
================================================
[ЭТАП 3]: Пересчёт рейтингов НАБОРОВ (SetKit)...
================================================
✓ Обнулены рейтинги у 27 наборов
✓ Найдено 27 наборов для ранжирования
...
...
========================================================================================================================
НАБОР: Элит (ID: 3)
========================================================================================================================
Параметр Значение Ранг (0..1) Вклад
------------------------------------------------------------------------------------------------------------------------
Актуальность свежий 0.375 *
Водоотлив ✓ Да 1.000 *****
Гибкость скидок 0 вариантов 0.500 **
Доставка ✓ Да 1.000 *****
Климат-контроль ✓ Да 1.000 *****
Монтаж ✓ Да 1.000 *****
Откос ✓ Да 1.000 *****
Подоконник ✓ Да 1.000 *****
Размер скидок 0.0% 0.500 **
Число предложений 46 шт 0.250 *
------------------------------------------------------------------------------------------------------------------------
ИТОГО: Рейтинг = 4.16/5.0 ****
...
...
[OK!] ПЕРЕСЧЁТ РЕЙТИНГОВ ЗАВЕРШЁН УСПЕШНО!
• Обновлено профилей: 94
• Обновлено стеклопакетов: 97
• Обновлено наборов: 27
Оркестрация и reload веб-сервера
Важно:
- reload веб-сервера не встроен в management-команды;
- это отдельная операция окружения.
Пример для systemd + gunicorn:
sudo systemctl reload gunicorn
Рекомендуемый batch-сценарий:
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_prerender --force
poetry run python oknardia/manage.py generate_sitemaps
sudo systemctl reload gunicorn
Cron/systemd timer (пример)
Пример cron (раз в сутки в 03:20):
20 3 * * * cd /Users/e-serg/PRJ/2022-oknardia && poetry run python oknardia/manage.py regenerate_seria_prerender --force && poetry run python oknardia/manage.py generate_sitemaps >> /var/log/oknardia-maintenance.log 2>&1
Если нужен reload после batch, добавляй отдельной строкой/шагом оркестратора.
Диагностика
Быстрая проверка конфигурации:
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py check
Типовые причины проблем:
- нет прав записи в директории
templates/seria_info/preparedилиMEDIA_ROOT/_serv_sitemap; - устаревшее виртуальное окружение / неустановленные зависимости;
- запуск не из того каталога.
План миграции /service/* -> management commands
Текущее направление:
- все тяжелые и административные операции переносить из HTTP в management-команды;
/service/*оставлять только как thin UI/мониторинг или убрать полностью.
См. также:
SETUP.mdREADME.md