add: Django Management Command для "склейки" корневых серий типового строительства

This commit is contained in:
2026-05-14 00:27:17 +03:00
parent 998e6caf8f
commit b27d6f0546
2 changed files with 414 additions and 8 deletions

View File

@@ -9,10 +9,11 @@
## Каталог команд
1. `generate_sitemaps` — оффлайн генерация sitemap-файлов.
2. `regenerate_seria_prerender` — оффлайн пересборка pre-render шаблонов для `catalog_seria_info`.
3. `populate_seo_fields` — автозаполнение SEO-полей блога из существующих данных.
4. `make_rating` — пересчёт рейтингов профилей и стеклопакетов методом Манна-Уитни.
1. `regenerate_seria_roots` — пересчет корневых серий (иерархия и консолидация).
2. `generate_sitemaps` — оффлайн генерация sitemap-файлов.
3. `regenerate_seria_prerender` — оффлайн пересборка pre-render шаблонов для `catalog_seria_info`.
4. `populate_seo_fields` — автозаполнение SEO-полей блога из существующих данных.
5. `make_rating` — пересчёт рейтингов профилей и стеклопакетов методом Манна-Уитни.
## Общие правила запуска
@@ -28,7 +29,210 @@ cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py <command> [args]
```
## 1) Команда `generate_sitemaps`
## 1) Команда `regenerate_seria_roots`
Назначение:
- пересчитать корневые серии (root) для всей иерархии серий домов.
- консолидировать различные написания одной и той же серии в одну "корневую" серию.
### Контекст
На разных источниках данные о типовых сериях домов были записаны с разными орфографическими вариантами.
Например серия **II-57** могла быть обозначена как:
- `2-57` (цифра вместо кириллицы)
- `И-57` (кириллица И вместо латинской II)
- `П-57` (опечатка)
- и т.п.
При парсинге данных эти варианты могли оказаться в БД как отдельные серии, хотя на самом деле это одна и та же серия.
Функция `regenerate_seria_roots` связывает все эти варианты (алиасы) с одной **корневой** серией.
### Когда это нужно
При добавлении новых адресов и серий типового строительства, при ручном редактировании иерархии серий в админке,
при загрузке новых данных с разными орфографическими вариантами серий. Кроме того, если для уже существующих в базе
серий будут получены данные о типовых размерах оконных проёмов и типов квартирах (сейчас в базе около 4500 серий, из
них всего 31 корневых серий и 1957 серий с найденным корнем... ещё 2502 неописанных серии без корня, т.е. больше
половины, могут пополнить каталог Окнардии.
### Как это работает
1. **Этап 1**: Находит "корневые" серии (root series) — те, что реально используются в таблице `Apartment_Type`
(т.е. у которых есть квартиры). Для каждой такой серии устанавливает `kRoot_id = own_id`.
2. **Этап 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 | Алиас (через родителя)
```
### Базовый запуск
```bash
cd /Users/e-serg/PRJ/2022-oknardia
poetry run python oknardia/manage.py regenerate_seria_roots
```
### Параметры запуска
**`--verbosity 0`** — только ошибки (минимум информации):
```bash
poetry run python oknardia/manage.py regenerate_seria_roots --verbosity 0
```
**`--verbosity 1`** — точки/плюсы (стандартный режим):
```bash
poetry run python oknardia/manage.py regenerate_seria_roots
# или явно
poetry run python oknardia/manage.py regenerate_seria_roots --verbosity 1
```
**`--verbosity 2`** — подробный вывод (названия серий):
```bash
poetry run python oknardia/manage.py regenerate_seria_roots --verbosity 2
```
**`--verbosity 3`** — очень подробный вывод в виде таблицы:
```bash
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с
```
### Когда запускать
- **После первого развертывания** — консолидировать иерархию серий.
- **После ручного редактирования иерархии** (добавления родитель-потомков в админку).
- **После загрузки новых данных** с разными орфографическими вариантами серий.
- **По расписанию** (опционально, например раз в месяц):
```bash
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** — если нужно очистить поле (перед запуском рекомендуется бэкап):
```sql
UPDATE oknardia_seria_info SET kRoot_id = NULL;
```
- **Проверка результатов** — после запуска можно проверить:
```bash
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`.
@@ -76,7 +280,7 @@ location = /sitemap.xml {
}
```
## 2) Команда `regenerate_seria_prerender`
## 3) Команда `regenerate_seria_prerender`
Назначение:
- пересобрать pre-render шаблоны для страниц серий (`catalog_seria_info`) в каталоге `seria_info/prepared/`.
@@ -114,7 +318,7 @@ poetry run python oknardia/manage.py regenerate_seria_prerender --seria-id 843 -
- после массового обновления данных серий/окон/квартир;
- после очистки `seria_info/prepared/`.
## 3) Команда `populate_seo_fields`
## 4) Команда `populate_seo_fields`
Назначение:
- автозаполнить SEO-поля (`sSlug`, `sMetaDescription`, `sMetaKeywords`) для всех существующих записей блога.
@@ -226,7 +430,7 @@ print(f'Пусто sMetaKeywords: {posts.filter(sMetaKeywords=\"\").count()}')
- ✅ **Откат через SQL** — если нужно очистить, используй: `UPDATE oknardia_blogposts SET sSlug='', sMetaDescription='', sMetaKeywords='';`
- ✅ **Всегда используй `--dry-run`** перед первым запуском для проверки.
## 4) Команда `make_rating`
## 5) Команда `make_rating`
Назначение:
- пересчитать рейтинги оконных профилей, стеклопакетов и наборов услуг используя адаптированный метод Манна-Уитни (Mann-Whitney U Step Rank).