diff --git a/.env.sample b/.env.sample index 7de66ec..2d19ba7 100644 --- a/.env.sample +++ b/.env.sample @@ -1,5 +1,6 @@ # Django Configuration Example -# Копируйте этот файл в .env.local и заполните реальные значения +# Все настройки читаются из переменных окружения (DEV/PROD без распознавания хоста) +# Для локальной разработки можно скопировать файл в .env.local и экспортировать его. # ============================================================================ # DJANGO @@ -15,19 +16,36 @@ DEBUG=False # Допустимые хосты (разделены запятой без пробелов) ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com +# Базовый публичный URL сайта (используется для абсолютных URL в sitemap.xml) +SITE_BASE_URL=https://yourdomain.com + +# Админы для email-оповещений Django (формат: Имя:email,Имя2:email2) +ADMINS=Admin:admin@example.com + +# URL для доступа к админке Django (можно сменить для безопасности, чтобы боты не могли её найти) +ADMIN_URL=admin/ + # ============================================================================ # DATABASE # ============================================================================ -# Database backend (по умолчанию mysql) -DATABASE_ENGINE=django.db.backends.mysql +# Database backend (по умолчанию SQLite) +DATABASE_ENGINE=django.db.backends.sqlite3 -# Database connection -DATABASE_HOST=localhost -DATABASE_PORT=3306 -DATABASE_NAME=django_oknardia -DATABASE_USER=web -DATABASE_PASSWORD=your-db-password-here +# Имя/путь базы данных: +# - для SQLite: только имя файла (полный путь соберется в settings.py через PROJECT_ROOT/database) +# - для MySQL/MariaDB: имя базы +DATABASE_NAME=oknadria.sqlite3 + +# Для MySQL/MariaDB (используются, если DATABASE_ENGINE=django.db.backends.mysql) +# DATABASE_HOST=localhost +# DATABASE_PORT=3306 +# DATABASE_USER=name-for-db-user +# DATABASE_PASSWORD=your-db-password-here + + +# Подкаталог в MEDIA_ROOT, где хранится кеш sitemap-файлов +SITEMAP_SUBDIR=_serv_sitemap # ============================================================================ # EMAIL @@ -40,6 +58,7 @@ EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend EMAIL_HOST=smtp.example.com EMAIL_PORT=587 EMAIL_USE_TLS=True +EMAIL_USE_SSL=False EMAIL_HOST_USER=your-email@example.com EMAIL_HOST_PASSWORD=your-email-password @@ -100,7 +119,7 @@ LOG_LEVEL=INFO # ============================================================================ # 1. Скопируйте этот файл: -# cp .env.example .env.local +# cp .env.sample .env.local # # 2. Отредактируйте значения в .env.local: # nano .env.local @@ -108,9 +127,8 @@ LOG_LEVEL=INFO # 3. Убедитесь, что .env.local в .gitignore: # grep ".env" .gitignore # -# 4. Используйте python-dotenv для загрузки переменных в settings.py: -# from dotenv import load_dotenv -# load_dotenv() +# 4. Экспортируйте переменные перед запуском Django: +# set -a; source .env.local; set +a # # ВАЖНО: # - НИКОГДА не коммитьте .env.local или файлы с реальными значениями в git! diff --git a/.gitignore b/.gitignore index ddebaa3..70518bb 100755 --- a/.gitignore +++ b/.gitignore @@ -132,4 +132,35 @@ venv.bak/ dmypy.json # Pyre type checker -.pyre/ \ No newline at end of file +.pyre/ + +# MacOS specific files +.DS_Store + +# Database dumps and backups (CRITICAL - NEVER commit production data!) +SQL/ +*.sql +*.dump +*.backup +*.sql.gz +db.json +db.json.zip + +# API keys, certificates, and credentials +*.key +*.pem +*.p12 +*.p8 +*.crt +*.cert + +# IDE and editor specific +.vscode/settings.json +.idea/vcs.xml +.idea/inspectionProfiles/ + +# Project specific ignore patterns +.github/ +.log/ +.logs/ +sitemap*.xml diff --git a/AGENTS.md b/AGENTS.md index 3c3db46..fb30df5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -213,6 +213,7 @@ python manage.py collectstatic # собрать статику для 5. **Foreign Key ON_DELETE**: используется в основном `DO_NOTHING` и `SET_NULL`, будь осторожен при удалении 6. **Двойной хост**: убедись, что используешь правильные переменные из `my_secret.py` для текущей машины 7. **Индексирование БД**: большинство полей для поиска уже имеют `db_index=True`, но проверь при добавлении фильтров +8. **SEO-даты и свежесть контента**: при переделке вьюх/шаблонов отдельно проверяй, нужны ли ещё `last_update`, `PUB_DAT`, `Date4Meta` и `Last4Meta`; если дата не участвует в смысловой логике страницы, лучше оставить базовые `{% now %}` из `base.html`, а не тащить лишний контекст во вьюху и не нагружать бекенд. ## Реферальные ссылки (для более глубокого изучения) diff --git a/MANAGEMENT_RUNBOOK.md b/MANAGEMENT_RUNBOOK.md new file mode 100644 index 0000000..e5f70c2 --- /dev/null +++ b/MANAGEMENT_RUNBOOK.md @@ -0,0 +1,907 @@ +# MANAGEMENT_RUNBOOK.md + +Единый runbook по management-командам проекта. + +Документ отвечает на 3 вопроса: +- что запускать; +- когда запускать; +- как безопасно откатываться/повторять запуск. + +## Каталог команд + +1. `regenerate_seria_roots` — пересчет корневых серий (иерархия и консолидация). +2. `generate_map_js` — генерация JavaScript для карт с геоданными зданий. +3. `generate_sitemaps` — оффлайн генерация sitemap-файлов. +4. `regenerate_seria_prerender` — оффлайн пересборка pre-render шаблонов для `catalog_seria_info`. +5. `populate_seo_fields` — автозаполнение SEO-полей блога из существующих данных. +6. `make_rating` — пересчёт рейтингов профилей и стеклопакетов методом Манна-Уитни. + +## Общие правила запуска + +- Запускать команды из корня репозитория. +- Для локального/CI запуска использовать `poetry`. +- Не запускать тяжелые операции через HTTP-эндпоинты `/service/*`. +- Перезапуск веб-сервера (`gunicorn`/`uWSGI`) делать отдельным шагом оркестрации, а не из кода Django. + +Базовый шаблон запуска: + +```bash +cd /Users/e-serg/PRJ/2022-oknardia +poetry run python oknardia/manage.py [args] +``` + +## 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_map_js` + +Назначение: +- сгенерировать JavaScript-файл для отрисовки карты всех зданий типовых серий в Яндекс.Картах. +- файл содержит геоданные (latitude/longitude), ID адресов, привязку к сериям и информацию для balloon-окон на картах. + +### Что происходит + +1. **Сбор геоданных** — для всех корневых серий (где `id = kRoot_id`) + - Запрашиваются здания из таблицы `Building_Info` с non-zero координатами + - Для каждого здания собирается: широта, долгота, ID адреса, адрес в латинице, ID серии + +2. **Генерация JavaScript** — на основе шаблона `service/JavaScript4AllSeriaMap.js.html` + - Генерируется массив цветов для каждой серии + - Объявляются переменные с ID и названиями серий + - Инициализируется Yandex.Maps с PlaceMarks для каждого здания + +3. **Минификация через Terser** — уменьшение размера JavaScript + - Удаляются ненужные пробелы и переносы строк + - Сокращаются имена переменных (mangling) + - Удаляются console.log и debugger + +4. **Запись в файлы**: + - `public/static/js/4maps/_ALL_seria_on_map.js` — исходный форматированный файл (715 KB) + - `public/static/js/4maps/_ALL_seria_on_map.mini.js` — минифицированный файл (639 KB) + +### Оптимизация размера + +Файл был оптимизирован в три этапа: + +| Этап | Размер | Сжатие | +|------|--------|--------| +| Исходный (2016 год) | 2.5 MB | — | +| **Уровень 1**: функция-фабрика `m()` | 715 KB | **71%** | +| **Уровень 2**: Terser минификация | 639 KB | +10.6% | +| **Уровень 3**: Gzip в браузере | 188 KB | +29.4% | +| **Итого сжатие** | **188 KB** | **92.5%** | + +> **Примечание**: Gzip применяется автоматически браузером и веб-сервером при наличии в заголовках `Content-Encoding: gzip` + +Содержимое: +- **Маркеры на карте**: 18,228 зданий +- **Серии с цветами**: 31 +- **Корневые серии**: 31 + +### Базовый запуск + +```bash +cd /Users/e-serg/PRJ/2022-oknardia +poetry run python oknardia/manage.py generate_map_js +``` + +### Параметры запуска + +**`--force`** — пересгенерировать файл (перезаписать если существует): + +```bash +poetry run python oknardia/manage.py generate_map_js --force +``` + +**`--verbosity 2`** — подробный вывод со статистикой: + +```bash +poetry run python oknardia/manage.py generate_map_js --verbosity 2 +``` + +### Когда запускать + +- **После первого развертывания** — создать файл карты один раз. +- **После добавления новых зданий** в БД (через парсеры или импорт). +- **По расписанию** (опционально, если здания редко добавляются): + ```bash + 0 3 * * 0 cd /home/user/app-path/2022-oknardia && poetry run python oknardia/manage.py generate_map_js >> /var/log/oknardia-map-js.log 2>&1 + ``` + +### Пример вывода + +``` +=== ГЕНЕРАЦИЯ JAVASCRIPT ДЛЯ КАРТ === + +Этап 1: Сбор информации о корневых сериях... +✓ Найдено корневых серий: 31 + +Этап 2: Генерация единого JS-файла для ВСЕ серий... +✓ Написан исходный файл: _ALL_seria_on_map.js + Размер: 734.0 KB + +Этап 3: Минификация JavaScript (rjsmin)... +[*] Минификация успешна! + Исходный файл: 734.015 KB + Минифицированный: 732.952 KB + Сжатие: 0.14% + Время: 0.0017с +[i] Полная статистика по сериям: + - Жилых м²: 125,749,341 + - Муниципальных м²: 11,302,860 + - Жильцов: 6,342,742 + - Квартир: 2,769,800 + +=== РЕЗУЛЬТАТЫ === +✓ Серий обработано: 31 +✓ Зданий на карте: 18228 +✓ JS-файлов создано: 2 (исходный + минифицированный) +✓ Исходный файл: _ALL_seria_on_map.js +✓ Минифицированный: _ALL_seria_on_map.mini.js +✓ Обфускация: Base64 кодирование координат + +[OK] Генерация завершена! Время: 1.10с +``` + +## 3) Команда `generate_sitemaps` + +Назначение: +- пересобрать `sitemap.xml` и chunk-файлы в `MEDIA_ROOT/_serv_sitemap`. + +Базовый запуск: + +```bash +cd /Users/e-serg/PRJ/2022-oknardia +poetry run python oknardia/manage.py generate_sitemaps +``` + +Запуск с параметрами: + +```bash +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) + +```nginx +# Корневой sitemap.xml (для привычного для поисковиков URL) +location = /sitemap.xml { + alias /<путь-к-каталогку-с-докер-приложением>/media/_serv_sitemap/sitemap.xml; + default_type application/xml; + add_header Cache-Control "public, max-age=300"; +} +``` + +## 4) Команда `regenerate_seria_prerender` + +Назначение: +- пересобрать pre-render шаблоны для страниц серий (`catalog_seria_info`) в каталоге `seria_info/prepared/`. + +Проверка без записи файлов: + +```bash +cd /Users/e-serg/PRJ/2022-oknardia +poetry run python oknardia/manage.py regenerate_seria_prerender --dry-run +``` + +Пересборка только отсутствующих файлов: + +```bash +cd /Users/e-serg/PRJ/2022-oknardia +poetry run python oknardia/manage.py regenerate_seria_prerender +``` + +Принудительная пересборка всех root-серий: + +```bash +cd /Users/e-serg/PRJ/2022-oknardia +poetry run python oknardia/manage.py regenerate_seria_prerender --force +``` + +Выборочная пересборка: + +```bash +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/`. + +## 5) Команда `populate_seo_fields` + +Назначение: +- автозаполнить SEO-поля (`sSlug`, `sMetaDescription`, `sMetaKeywords`) для всех существующих записей блога. + +Используется: +- при первом развертывании новой версии с автогенерацией SEO-полей; +- при восстановлении из бэкапа где SEO-поля пусты; +- при изменении логики автогенерации (с флагом `--force`). + +### Базовый запуск + +Заполнить только пустые SEO-поля (стандартный вариант): + +```bash +cd /Users/e-serg/PRJ/2022-oknardia +poetry run python oknardia/manage.py populate_seo_fields +``` + +### Параметры запуска + +**`--dry-run`** — только показать что будет сделано (без сохранения в БД): + +```bash +poetry run python oknardia/manage.py populate_seo_fields --dry-run +``` + +**`--force`** — переполнить ВСЕ SEO-поля, даже уже заполненные: + +```bash +poetry run python oknardia/manage.py populate_seo_fields --force +``` + +**`--clean`** — очистить все SEO-поля перед заполнением (для переделки): + +```bash +poetry run python oknardia/manage.py populate_seo_fields --clean +``` + +**Комбинация флагов** — сухой прогон переполнения всех полей: + +```bash +poetry run python oknardia/manage.py populate_seo_fields --dry-run --force +``` + +### Что заполняется + +| Поле | Источник | Результат | +|------|----------|-----------| +| `sSlug` | `sPostHeader` | URL-безопасный слаг (max 200 символов) | +| `sMetaDescription` | `sPostContent` | Первые 160 символов (исключая теги ``) | +| `sMetaKeywords` | `sPostHeader` | Заголовок + префикс "oknardia, окнардия, блог, публикация" (max 256 символов) | + +Пример результата: + +```python +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-полей. + +### Пример полного сценария + +```bash +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`** перед первым запуском для проверки. + +## 6) Команда `make_rating` + +Назначение: +- пересчитать рейтинги оконных профилей, стеклопакетов и наборов услуг используя адаптированный метод Манна-Уитни (Mann-Whitney U Step Rank). +- сохранить результаты в поля `fProfileRating`, `fGlazingRating`, `fSetRating` (0.0 … 5.0 звёзд). +- заполнить JSON-состав рейтинга (детальный разбор по каждому параметру) в поля `sProfileDescription`, `sGlazingDescription`, `sSetDescription`. +- алгоритм рассчитывает три этапа ранжирования: профили → стеклопакеты → наборы (которые зависят от профилей и стеклопакетов). + +### Базовый запуск + +Пересчитать рейтинги всех профилей и стеклопакетов (стандартный режим): + +```bash +cd /Users/e-serg/PRJ/2022-oknardia +poetry run python oknardia/manage.py make_rating +``` + +### Параметры запуска + +**`--verbosity 0`** — минимум информации (только ошибки): +**`--verbosity 1`** — стандартная информация (по умолчанию): +**`--verbosity 3`** — очень подробный вывод (для отладки, для каждого профиля/стеклопакета таблица): + +Пример использования с параметром `--verbosity`: + +```bash +poetry run python oknardia/manage.py make_rating --verbosity 3 | head -500 +``` + +### АЛГОРИТМ: Метод Манна-Уитни (Mann-Whitney U Step Rank) + +Команда использует адаптированный вариант критерия Манна-Уитни для ранжирования параметров качества оконных +предложений и комопнентов (профилей, стеклопакетов, наборов услуг) на основе их технических характеристик +и популярности у поставщиков. + +#### Как это работает: + +1. **Сортировка объектов** по одному параметру (например, по теплопередаче): + - Профиль A: 0.60 Ro → ранг = 0.0 + - Профиль B: 0.60 Ro → ранг = 0.0 (то же значение, ранг не меняется) + - Профиль C: 0.80 Ro → ранг = 1.0 (новое значение, добавляем вес параметра) + - Профиль D: 0.95 Ro → ранг = 2.0 (ещё новое значение) + +2. **Направление ранжирования** определяется флагом `revers`: + - `revers=False` — **БОЛЬШЕ = ЛУЧШЕ** (например, теплопередача, звукоизоляция) + - `revers=True` — **МЕНЬШЕ = ЛУЧШЕ** (например, высота в проёме для прочности) + +3. **Нормализация рангов** к диапазону 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 + +4. **Суммирование рангов** по всем параметрам: + - TmpRating = Σ(ранг_параметра × вес_параметра) + +5. **Преобразование в звёзды** (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 ⭐**: минимальный пакет или устаревшие предложения (давно не обновлялись). + +### Когда запускать + +- **После первого развертывания** — заполнить рейтинги всех профилей, стеклопакетов и наборов. +- **После изменения каталога** (добавление нового профиля/стеклопакета/набора). +- **После уточнения характеристик** (например, поставщик предоставил новые данные). + ```bash + poetry run python oknardia/manage.py make_rating + ``` + +- **По расписанию** (например, ежемесячно, чтобы пересчитать популярность): + ```bash + 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** — если нужно установить нулевые значения (перед запуском рекомендуется бэкап базы): + ```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: + +```bash +sudo systemctl reload gunicorn +``` + +Рекомендуемый batch-сценарий: + +```bash +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): + +```bash +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, добавляй отдельной строкой/шагом оркестратора. + +## Диагностика + +Быстрая проверка конфигурации: + +```bash +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.md` +- `README.md` + diff --git a/README.md b/README.md index e356d16..f078496 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,54 @@ # Оконный агрегатор «Окнардия» -### Переделка под Python 3.8 и Django 4.1 +**Окнардия** — веб-сервис для сравнения цен на установку оконных конструкций в типовых многоквартирных домах России. + +* **Пользователь, желающий заменить окна**, вводит адрес дома → система распознаёт серию строения → выдаёт типовые размеры оконных проёмов → показывает предложения от поставщиков на установку (замену) окон, с ценами, характеристиками компонентов и условиями. + Алгоритмические рейтинги защищают потенциального покупателя от возможных накруток отзывов и позволяют сравнивать предложения по объективным характеристикам. + +* Для **производителей и поставщиков окон** платформа — это канал прямого доступа к целевой аудитории в конкретном районе города. +Они размещают свои предложения (компоненты, наборы, цены) и конкурируют на равных условиях. Масштабируемый каталог позволяет охватить +множество адресов типовой застройки, а система алгоритмического рейтинга (нет отзывов клиентов, а значит накрутка отзывов невозможна) ранжирует предложения исключительно по характеристикам и условиям предложений. + +**Стек**: Python 3.12+ · Django 5.2+ · SQLite/MariaDB · Bootstrap 3.3 · jQuery · Yandex Maps API + +--- + +### Переделка под Python 3.12 и Django 5.2.13 (апрель-май 2026) + +Сделано: +* Переход проекта под Python 3.12 и Django 5.2.13, удаление устаревших зависимостей, унификация функций и хелперов. +* Перехода на SQLite (возможно, после нагрузочного тестирования переход обратно на mariaDB или PostgreSQL). +* Переделаны все raw SQL-запросы на ORM для лучшей поддержки разных СУБД в будущем. +* Все сервисные функции из `service/` вынесены в management-команды. +* Переработаны все шаблоны с целью SEO- и LLM-оптимизацим: более корректные meta-теги, разметка schema.org + через `JSON-LD`, оптимизирована структура "хлебных крошек" и изменение роутинга. +* Облегчение шаблона `base.html`: блок логин-логаут подгружается через AJAX только по клику, модуль авторизации + вынесен в отдельный JS-файл (`/static/js/auth.js`), счетчики посещений перенесены в подгружаемый JS. +* Шаблоны `report/report_last_user_visit.html` больше не требуют серверного рендеринга, а формируются + на стороне клиента из кук. +* Добавлены SEO-поля блогов. + +### Планы, задачи, маркеры на будущее: + +* Оптимизация кеширования pre-render шаблонов: настроить cronjob для ежедневной/еженедельной очистки `seria_info/prepared/`. +* Улучшение администрирования в блогах (Codemirror 6, Типографф). +* Упаковать всё в контейнеры: бакенд Django + Gunicorn + WhiteNoise... +* CI/CD через gitea + Watchtower для автоматического деплоя при пуше тега `v*.*.*` в репозиторий. +* Фронтенд: перейти на новый Bootstrap 5, добавить интерактивные элементы через HTMX + Alpine, сделать адаптивность для мобильных устройств. Убрать jQuery и старые плагины, заменить на современные аналоги. +* Оптимизация для мобильных устройств: адаптивный дизайн, оптимизация изображений, улучшение производительности. +* Переход проекта под Python 3.14 и Django 6.x. +* Нагрузочное тестирование (рпи необходимости переход с SQLite на PostgreSQL в продакшене). + +# См. также: + +* [`MANAGEMENT_RUNBOOK.md`](MANAGEMENT_RUNBOOK.md) – единый runbook по management-командам и batch-операциям, сниппеты. +* [`AGENTS.md`](AGENTS.md) – контекст проекта для AI-ассистентов (архитектура, конвенции, рабочие сценарии). +* [`SETUP.md`](SETUP.md) – пошаговая настройка окружения, запуск проекта и базовые команды разработки. + + +--- +Легаси-материалы старого README, которые могут быть полезны для понимания устройства проекта и его +администрирования, а также для будущей реорганизации документации. ### Немного о механике кеширования: @@ -13,63 +61,18 @@ Эти картинки создаются автоматически. Можно не удалять. Даже если какая-то схема открывания или размер проёма станет неактуальным, лишняя картинка просто будет лежать в папке (вдруг такой проём появится снова). -#### Кеширование шаблонов +#### Кеширование pre-render шаблонов серий домов -В папке `oknardia/oknardia/templates/seria_info/prepared` создаются пре-рендер шаблоны с информацией о сериях домов. +В папке `oknardia/templates/seria_info/prepared/` создаются пре-рендер HTML-шаблоны с информацией о сериях домов. -Эти шаблоны надо периодически удалять. Они нужны для скорости. Но если меняются данные по серии, размерам окон, появляются -новые коммерческие предложения -- их надо удалять и тогда построятся новые. Вообще на быстрых серверах скорость может -не быть проблемой, так что возможно стоит просто настроить через crone ежедневное или еженедельное удаление этих -пре-рендер шаблонов. При обращении к соответсвующий страницам эти шаблоны будут пересозданы автоматически. +Эти шаблоны создаются при первом обращении к странице серии и хранятся для ускорения последующих запросов. +**Важно**: их надо периодически удалять, особенно если меняются: +* данные по сериям и размерам окон +* коммерческие предложения и цены +* рейтинги компонентов + +**Рекомендация**: настроить cronjob на ежедневное или еженедельное удаление этих файлов. При обращении к соответствующим +страницам эти шаблоны будут пересозданы автоматически. На быстрых серверах можно вообще отключить кеширование, если оно +не критично для производительности. -### Некоторые заметки относительно разработки (DEV) на macOS: - -Т.к. MariaDB "сидит" в контейнере Dockers могут возникнуть трудности при установке коннектора к базам данных MySQL/MariaDB. Примерно такие: -```txt -Collecting mysqlclient - Using cached mysqlclient-2.1.1.tar.gz (88 kB) - Preparing metadata (setup.py) ... error - error: subprocess-exited-with-error - - × python setup.py egg_info did not run successfully. - │ exit code: 1 - ╰─> [16 lines of output] - /bin/sh: mysql_config: command not found - /bin/sh: mariadb_config: command not found - /bin/sh: mysql_config: command not found - Traceback (most recent call last): - File "", line 2, in - File "", line 34, in - File "/private/var/folders/jh/gbhf3vk11svg9w4mvhntlb7c0000gn/T/pip-install-nu5ar2g2/mysqlclient_a07e3d9dbe514c7793dc71f1183dda19/setup.py", line 15, in - metadata, options = get_config() - File "/private/var/folders/jh/gbhf3vk11svg9w4mvhntlb7c0000gn/T/pip-install-nu5ar2g2/mysqlclient_a07e3d9dbe514c7793dc71f1183dda19/setup_posix.py", line 70, in get_config - libs = mysql_config("libs") - File "/private/var/folders/jh/gbhf3vk11svg9w4mvhntlb7c0000gn/T/pip-install-nu5ar2g2/mysqlclient_a07e3d9dbe514c7793dc71f1183dda19/setup_posix.py", line 31, in mysql_config - raise OSError("{} not found".format(_mysql_config_path)) - OSError: mysql_config not found - mysql_config --version - mariadb_config --version - mysql_config --libs - [end of output] - - note: This error originates from a subprocess, and is likely not a problem with pip. -error: metadata-generation-failed - -× Encountered error while generating package metadata. -╰─> See above for output. - -note: This is an issue with the package mentioned above, not pip. -hint: See above for details. -``` - -Починить проблему можно воспользовавшись ([рецептом со StackOverflow](https://stackoverflow.com/a/44268445/1504067)): -```shell -brew install mariadb-connector-c -# sudo ln -s /usr/local/opt/mariadb-connector-c/bin/mariadb_config /usr/local/bin/mysql_config - -pip install mysqlclient - -# rm /usr/local/bin/mysql_config -brew unlink mariadb-connector-c -``` \ No newline at end of file diff --git a/SETUP.md b/SETUP.md index 2f55f00..ee01922 100644 --- a/SETUP.md +++ b/SETUP.md @@ -233,6 +233,26 @@ python manage.py remove_stale_contenttypes # Удалить устаревши # Служебные python manage.py check # Проверить конфигурацию python manage.py check --deploy # Проверка для продакшена +python manage.py generate_sitemaps # Оффлайн генерация sitemap XML +python manage.py regenerate_seria_prerender --dry-run # Проверка пересборки pre-render шаблонов серий +python manage.py regenerate_seria_prerender --force # Принудительная пересборка pre-render шаблонов серий +``` + +### Пересборка pre-render шаблонов серий (рекомендуемый сценарий) + +Шаблоны для `catalog_seria_info` пересобираются оффлайн management-командой, без reload из кода Django. + +```bash +cd /path/to/project +poetry run python oknardia/manage.py regenerate_seria_prerender --force +# затем (опционально) один внешний reload процесса приложения, если это требуется вашей конфигурацией +# sudo systemctl reload gunicorn +``` + +Для выборочной пересборки используйте `--seria-id` несколько раз: + +```bash +poetry run python oknardia/manage.py regenerate_seria_prerender --seria-id 843 --seria-id 2100 --force ``` ## 📚 Дополнительные ресурсы @@ -240,7 +260,6 @@ python manage.py check --deploy # Проверка для продак - [Django документация](https://docs.djangoproject.com/en/stable/) - [AGENTS.md](./AGENTS.md) — архитектура и конвенции проекта - [README.md](./README.md) — основная информация о проекте -- [SECURITY_AUDIT_REPORT.md](./SECURITY_AUDIT_REPORT.md) — отчёт безопасности ## ❓ Решение проблем diff --git a/database/.gitignore b/database/.gitignore new file mode 100644 index 0000000..c59ab23 --- /dev/null +++ b/database/.gitignore @@ -0,0 +1,3 @@ +# Это папака для хранения базы данных SQLite, не должна быть в репозитории. +*.* +* \ No newline at end of file diff --git a/logs/touch-reload.txt b/logs/touch-reload.txt deleted file mode 100644 index 56a6051..0000000 --- a/logs/touch-reload.txt +++ /dev/null @@ -1 +0,0 @@ -1 \ No newline at end of file diff --git a/oknardia/oknardia/migrations/0002_remove_win_mountdim_flap_config_and_more.py b/oknardia/oknardia/migrations/0002_remove_win_mountdim_flap_config_and_more.py new file mode 100644 index 0000000..38838cc --- /dev/null +++ b/oknardia/oknardia/migrations/0002_remove_win_mountdim_flap_config_and_more.py @@ -0,0 +1,34 @@ +# Generated by Django 5.2.13 on 2026-05-10 14:39 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('oknardia', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='blogposts', + name='sMetaDescription', + field=models.CharField(blank=True, default='', help_text='SEO: описание для мета-тега (до 160 символов). Если пусто, будет использоваться текст тизера из контента.', max_length=160, verbose_name='Meta описание'), + ), + migrations.AddField( + model_name='blogposts', + name='sMetaKeywords', + field=models.CharField(blank=True, default='', help_text='SEO: ключевые слова для мета-тега (до 256 символов). Если пусто, будет использоваться заголовок.', max_length=256, verbose_name='Meta ключевые слова'), + ), + migrations.AddField( + model_name='blogposts', + name='sSlug', + field=models.SlugField(blank=True, help_text='SEO: URL-friendly версия заголовка (автоматически генерируется, если оставить пусто)', max_length=200, verbose_name='Slug'), + ), + migrations.AlterField( + model_name='blogposts', + name='dPostDataBegin', + field=models.DateTimeField(db_index=True, default=datetime.datetime(2026, 5, 10, 17, 39, 4, 114851), help_text='Если установить будущую дату, то в назначеное время пост появится автоматически.', verbose_name='Опубликован от'), + ), + ] diff --git a/oknardia/oknardia/models.py b/oknardia/oknardia/models.py index e4c783f..d40335a 100644 --- a/oknardia/oknardia/models.py +++ b/oknardia/oknardia/models.py @@ -8,7 +8,8 @@ from datetime import date, datetime from django.utils import timezone from django.contrib.auth.models import User from oknardia.settings import * - +from web.add_func import sanitize_slug, safe_html_spec_symbols +import re # Таблица: Каталог профилей, стеклопакетов (добавлено 09.авг.2017) # create table oknardia_catalog2profile @@ -1033,6 +1034,28 @@ class BlogPosts(models.Model): db_index=False, verbose_name=u"Создано" ) + sMetaDescription = models.CharField( + max_length=160, + blank=True, + default=u"", + verbose_name=u"Meta описание", + help_text=u"SEO: описание для мета-тега (до 160 символов). Если пусто, будет использоваться текст тизера из контента." + ) + sMetaKeywords = models.CharField( + max_length=256, + blank=True, + default=u"", + verbose_name=u"Meta ключевые слова", + help_text=u"SEO: ключевые слова для мета-тега (до 256 символов). Если пусто, будет использоваться заголовок." + ) + sSlug = models.SlugField( + max_length=200, + db_index=True, + blank=True, + verbose_name=u"Slug", + help_text=u"SEO: URL-friendly версия заголовка (автоматически генерируется, если оставить пусто)" + ) + def __unicode__(self): # return u'%s (%s)' % (self.sPostHeader, datetime.strftime( @@ -1042,6 +1065,46 @@ class BlogPosts(models.Model): def __str__(self): return self.__unicode__() + def save(self, *args, **kwargs): + """Переопределённый метод save() для автоматической генерации слага и SEO-полей. + + При сохранении записи блога: + - Генерируется sSlug из sPostHeader если тот пуст + - Генерируется sMetaDescription из текста контента (тизер) + - Генерируется sMetaKeywords из заголовка + """ + # Шаг 1: Автоматически генерируем слаг из заголовка, если он не указан + if not self.sSlug and self.sPostHeader: + self.sSlug = sanitize_slug(self.sPostHeader, max_length=200) + + # Шаг 2: Автоматически генерируем sMetaDescription из контента (тизер) + if not self.sMetaDescription and self.sPostContent: + # Удаляем теги из контента + content_clean = re.sub(r'', '', self.sPostContent, flags=re.IGNORECASE) + + # Генерируем тизер (очищенный текст без HTML) + tizer = safe_html_spec_symbols(content_clean) + + # Обрезаем до 160 символов для мета-description + if len(tizer) > 160: + # Обрезаем слово целиком (не посередине) + tizer = tizer[:160].rsplit(' ', 1)[0] + '...' if ' ' in tizer[:160] else tizer[:160] + + self.sMetaDescription = tizer + + # Шаг 3: Автоматически генерируем sMetaKeywords из заголовка + if not self.sMetaKeywords and self.sPostHeader: + + # Берём заголовок и удаляем HTML-теги + header_clean = safe_html_spec_symbols(self.sPostHeader) + header_clean = header_clean.strip() + + # Генерируем ключевые слова: фиксированные + заголовок + fixed_keywords = u"oknardia, окнардия, блог, публикация" + self.sMetaKeywords = f"{fixed_keywords}, {header_clean}"[:256] + + super().save(*args, **kwargs) + class Meta: # db_table = "jtb_BlogPost" verbose_name = u"Запись в блоге каталоге" @@ -1323,6 +1386,8 @@ class Win_MountDim(models.Model): ) sFlapConfig = models.CharField( max_length=32, + blank=True, + default=u"", verbose_name=u"Открывание", help_text=u"Рекомендуемая гор.архитектурой конфигурации открывания (МЕТАЯЗЫК)") sDescripion = models.CharField( diff --git a/oknardia/oknardia/my_secret__sample.py b/oknardia/oknardia/my_secret__sample.py deleted file mode 100644 index a820c9b..0000000 --- a/oknardia/oknardia/my_secret__sample.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- coding: utf-8 -*- -""" -ШАБЛОН для my_secret.py - -ИНСТРУКЦИЯ: скопируйте этот файл в my_secret.py и заполните реальные значения. - -Пример: - cp oknardia/oknardia/my_secret.py.template oknardia/oknardia/my_secret.py - # затем отредактируйте значения в my_secret.py - -ВАЖНО: my_secret.py НИКОГДА не должен быть в git! -Используйте .gitignore для исключения файла. -""" - -# ============================================================================ -# РАЗРАБОТКА (DEV) - Хосты и сетевые настройки -# ============================================================================ - -# Хосты на которых может работать приложение (разработка) -MY_ALLOWED_HOSTS = [ - '127.0.0.1', - 'localhost', - 'your-dev-hostname.local', # ИЗМЕНИТЕ на ваше имя хоста -] - -# Допустимые хосты для разработки -MY_HOST_HOME1 = 'your-dev-hostname-windows' # ИЗМЕНИТЕ -MY_HOST_HOME2 = 'your-dev-hostname-mac' # ИЗМЕНИТЕ -MY_HOST_DEV = [MY_HOST_HOME1, MY_HOST_HOME2] - -# Хосты для продакшена (заполнять с осторожностью) -MY_HOST_PROD = [] # На продакшене используйте переменные окружения! - -# ============================================================================ -# БЕЗОПАСНОСТЬ - Django SECRET_KEY -# ============================================================================ - -# SECURITY WARNING: keep the secret key used in production secret! -# Сгенерируйте новый ключ с помощью: -# python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())' -MY_SECRET_KEY = 'ЗАПОЛНИТЕ_СЛУЧАЙНОЙ_СТРОКОЙ_БОЛЬШОЙ_ДЛИНЫ' - -# ============================================================================ -# АДМИНИСТРАТОРЫ - для оповещений об ошибках -# ============================================================================ - -MY_ADMINS = ( - ('Your Name', 'your-email@example.com'), - ('Admin Name', 'admin@example.com'), -) - -# ============================================================================ -# ПУТИ К ФАЙЛАМ - разработка -# ============================================================================ - -# путь к каталогу media (статика, для web-сервера nginx или apache) -MY_MEDIA_ROOT_DEV1 = 'M:\\path\\to\\your\\media\\' # Windows (если применимо) -MY_MEDIA_ROOT_DEV2 = '/path/to/your/media/' # Mac/Linux - ИЗМЕНИТЕ! - -# путь к каталогу static (статика, для web-сервера nginx или apache) -MY_STATIC_ROOT_DEV1 = 'M:\\path\\to\\your\\static' # Windows (если применимо) -MY_STATIC_ROOT_DEV2 = '/path/to/your/static' # Mac/Linux - ИЗМЕНИТЕ! - -# путь для кэш-блоков шаблонов -MY_STATIC_BASE_PATH_DEV1 = MY_STATIC_ROOT_DEV1 -MY_STATIC_BASE_PATH_DEV2 = MY_STATIC_ROOT_DEV2 - -# путь для sitemap файлов -MY_SITEMAP_ROOT_DEV1 = 'M:\\path\\to\\your\\public\\' # Windows (если применимо) -MY_SITEMAP_ROOT_DEV2 = '/path/to/your/public/' # Mac/Linux - ИЗМЕНИТЕ! - -# ============================================================================ -# ПУТИ К ФАЙЛАМ - продакшен -# ============================================================================ - -MY_MEDIA_ROOT_PROD = '/home/web/oknardia-ru/public/media/' # ЗАПОЛНИТЕ! -MY_STATIC_ROOT_PROD = '/home/web/oknardia-ru/public/static' # ЗАПОЛНИТЕ! -MY_STATIC_BASE_PATH_PROD = MY_STATIC_ROOT_PROD -MY_SITEMAP_ROOT_PROD = '/home/web/oknardia-ru/public/' # ЗАПОЛНИТЕ! - -# ============================================================================ -# EMAIL - Почтовый сервер (разработка) -# ============================================================================ - -# Email адреса для разработки -MY_EMAIL_DEV = 'dev-email@example.com' -MY_EMAIL_FROM_DEV = 'dev-email@example.com' -MY_EMAIL_HOST_USER_DEV = 'your-email@smtp.example.com' # ЗАПОЛНИТЕ! -MY_EMAIL_HOST_PASSWORD_DEV = 'YOUR_EMAIL_PASSWORD' # ЗАПОЛНИТЕ! -MY_EMAIL_HOST_DEV = 'smtp.example.com' # ЗАПОЛНИТЕ! (например: smtp.mail.ru) -MY_EMAIL_PORT_DEV = 587 # ЗАПОЛНИТЕ! (обычно 587 или 2525) - -# ============================================================================ -# EMAIL - Почтовый сервер (продакшен) -# ============================================================================ - -MY_EMAIL_PROD = MY_EMAIL_DEV -MY_EMAIL_FROM_PROD = MY_EMAIL_FROM_DEV -MY_EMAIL_HOST_USER_PROD = MY_EMAIL_HOST_USER_DEV # На продакшене используйте env переменные! -MY_EMAIL_HOST_PASSWORD_PROD = MY_EMAIL_HOST_PASSWORD_DEV # На продакшене используйте env переменные! -MY_EMAIL_HOST_PROD = MY_EMAIL_HOST_DEV -MY_EMAIL_PORT_PROD = MY_EMAIL_PORT_DEV - -# ============================================================================ -# БД MySQL/MariaDB - разработка -# ============================================================================ - -MY_DATABASE_HOST_DEV1 = 'localhost' # Офисный сервер разработки - ИЗМЕНИТЕ! -MY_DATABASE_HOST_DEV2 = 'localhost' # Домашний сервер разработки - ИЗМЕНИТЕ! - -MY_DATABASE_NAME_DEV = 'django_oknardia_dev' # ИЗМЕНИТЕ если нужно -MY_DATABASE_PORT_DEV = '3306' # Стандартный порт MySQL - -MY_DATABASE_USER_DEV = 'web' # ИЗМЕНИТЕ если нужно -MY_DATABASE_PASSWORD_DEV = 'YOUR_DB_PASSWORD' # ЗАПОЛНИТЕ! - -# ============================================================================ -# БД MySQL/MariaDB - продакшен -# ============================================================================ - -MY_DATABASE_HOST_PROD = 'localhost' # ЗАПОЛНИТЕ! (на продакшене) -MY_DATABASE_NAME_PROD = 'django_oknardia_prod' # ЗАПОЛНИТЕ! - -MY_DATABASE_PORT_PROD = '3306' -MY_DATABASE_USER_PROD = 'web' - -# ВНИМАНИЕ: На продакшене используйте переменные окружения или менеджер секретов! -MY_DATABASE_PASSWORD_PROD = '' # ОСТАВЬТЕ ПУСТО! Используйте переменные окружения! - -# ============================================================================ -# API ключи - Google Captcha -# ============================================================================ - -# Получите ключи на https://www.google.com/recaptcha/admin -# ВАЖНО: Никогда не коммитьте реальные ключи в git! -# PRIVATE ключ - это СЕКРЕТ, держите его в безопасности! -MY_CAPTCHA_PUBLIC_KEY = 'YOUR_CAPTCHA_PUBLIC_KEY_HERE' # ЗАПОЛНИТЕ! -MY_CAPTCHA_PRIVATE_KEY = 'YOUR_CAPTCHA_PRIVATE_KEY_HERE' # ЗАПОЛНИТЕ! (СЕКРЕТ!) - -# ============================================================================ -# API ключи - Yandex Maps -# ============================================================================ - -# Получите ключ на https://developer.tech.yandex.ru/ -MY_YANDEX_MAPS_API_KEY = 'YOUR_YANDEX_MAPS_API_KEY' - -# ============================================================================ -# uWSGI - Touch-reload файл (для перезагрузки при изменении кода) -# ============================================================================ - -MY_TOUCH_RELOAD_DEV1 = 'M:\\path\\to\\touch-reload.txt' # Windows (если применимо) -MY_TOUCH_RELOAD_DEV2 = '/path/to/logs/touch-reload.txt' # Mac/Linux - ИЗМЕНИТЕ! -MY_TOUCH_RELOAD_PROD = '/home/web/oknardia-ru/logs/touch-reload.txt' # ЗАПОЛНИТЕ! - -# ============================================================================ -# ИНСТРУКЦИЯ ПО ЗАПОЛНЕНИЮ -# ============================================================================ - -""" -1. СКОПИРУЙТЕ этот файл: - cp oknardia/oknardia/my_secret.py.template oknardia/oknardia/my_secret.py - -2. ОТРЕДАКТИРУЙТЕ значения, помеченные ИЗМЕНИТЕ! или ЗАПОЛНИТЕ! - -3. УБЕДИТЕСЬ, что мой_secret.py в .gitignore: - grep my_secret .gitignore - -4. НИКОГДА не коммитьте my_secret.py в git! - -5. На ПРОДАКШЕНЕ используйте переменные окружения: - export DJANGO_SECRET_KEY="..." - export DATABASE_PASSWORD="..." - и т.д. - -СОВЕТЫ: -- Сгенерируйте новый SECRET_KEY с помощью Python: - python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())' - -- Используйте менеджер паролей (LastPass, 1Password, Vault) для хранения учетных данных - -- Регулярно меняйте пароли БД и API ключи - -- На продакшене используйте отдельные более сильные пароли -""" - diff --git a/oknardia/oknardia/settings.py b/oknardia/oknardia/settings.py index 9a128d4..6125e9f 100644 --- a/oknardia/oknardia/settings.py +++ b/oknardia/oknardia/settings.py @@ -1,43 +1,57 @@ # -*- coding: utf-8 -*- -""" -Django settings for oknardia project. - -Generated by 'django-admin startproject' using Django 4.1.1. - -For more information on this file, see -https://docs.djangoproject.com/en/4.1/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/4.1/ref/settings/ -""" - from pathlib import Path -from oknardia.my_secret import * -import socket +import environ + + +def _env_admins(raw_items: list[str]) -> tuple[tuple[str, str], ...]: + # Формат: "Имя1:email1,Имя2:email2" + admins: list[tuple[str, str]] = [] + for item in raw_items: + if ":" not in item: + continue + admin_name, admin_email = item.split(":", maxsplit=1) + admin_name = admin_name.strip() + admin_email = admin_email.strip() + if admin_name and admin_email: + admins.append((admin_name, admin_email)) + return tuple(admins) + +def _normalize_admin_url(value: str) -> str: + """Приводит URL админки к виду `segment/` без ведущего слэша.""" + normalized = value.strip().lstrip('/') + if not normalized: + return 'admin/' + if not normalized.endswith('/'): + normalized += '/' + return normalized # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent +PROJECT_ROOT = BASE_DIR.parent +PUBLIC_ROOT = PROJECT_ROOT / 'public' +STATIC_SOURCE_ROOT = PUBLIC_ROOT / 'static' +env = environ.Env() +environ.Env.read_env(str(PROJECT_ROOT / '.env')) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'django-insecure-pd&1$j6z*1w#(j*16b+(@@#&2)+@x^^ot4)zqt-e67*1+$^qch' +SECRET_KEY = env( + var='DJANGO_SECRET_KEY', + default='django-insecure-pd&1$j6z*1w#(j*16b+(@@#&2)+@x^^ot4)zqt-e67*1+$^qch', +) +ADMIN_URL = _normalize_admin_url(env(var='ADMIN_URL', default='admin/')) # SECURITY WARNING: don't run with debug turned on in production! # ПРЕДУПРЕЖДЕНИЕ БЕЗОПАСНОСТИ: не работайте в режиме DEBUG в продашене! -if socket.gethostname() in MY_HOST_DEV: - DEBUG = TEMPLATE_DEBUG = True -else: - # Все остальные хосты (подразумевается продакшн) - DEBUG = TEMPLATE_DEBUG = True - # DEBUG = TEMPLATE_DEBUG = False +DEBUG = TEMPLATE_DEBUG = env.bool('DEBUG', default=False) -ALLOWED_HOSTS = MY_ALLOWED_HOSTS +ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['127.0.0.1', 'localhost']) # Настройки сообщений об ошибках когда все упало и т.п. -ADMINS = MY_ADMINS +ADMINS = _env_admins(env.list('ADMINS', default=[])) # Application definition @@ -51,7 +65,7 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', 'django.contrib.humanize', - # 'django.contrib.sitemaps', + 'django.contrib.sitemaps', 'oknardia.apps.OknardiaConfig', 'web.apps.WebConfig', @@ -67,6 +81,13 @@ MIDDLEWARE = [ 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] +# Разрешенные IP для отладки (нужно для django-debug-toolbar). +INTERNAL_IPS = env.list('INTERNAL_IPS', default=['127.0.0.1', 'localhost']) + +if DEBUG: + INSTALLED_APPS += ['debug_toolbar'] + MIDDLEWARE = ['debug_toolbar.middleware.DebugToolbarMiddleware', *MIDDLEWARE] + ROOT_URLCONF = 'oknardia.urls' TEMPLATES = [ @@ -115,61 +136,74 @@ DATETIME_FORMAT = 'Y-m-d H:i:s' # Статические файлы (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.1/howto/static-files/ -STATIC_URL = 'static/' -MEDIA_URL = 'media/' +STATIC_URL = '/static/' +MEDIA_URL = '/media/' -if socket.gethostname() in MY_HOST_DEV: # DEBUG: заменяем настройки прода, на настройки девопа - MEDIA_ROOT = MY_MEDIA_ROOT_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_MEDIA_ROOT_DEV2 - SITEMAP_ROOT = MY_SITEMAP_ROOT_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_SITEMAP_ROOT_DEV2 - # STATIC_ROOT = MY_STATIC_ROOT_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_STATIC_ROOT_DEV2 - STATICFILES_DIRS = [ - MY_STATIC_ROOT_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_STATIC_ROOT_DEV2, - ] - # путь к каталогу static (в эту переменную использовать для указания пути где будут делаться кэш-блоки для шаблонов) - STATIC_BASE_PATH = MY_STATIC_BASE_PATH_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_STATIC_BASE_PATH_DEV2 +MEDIA_ROOT = str(PUBLIC_ROOT / 'media') +# STATIC_ROOT отделен от исходной статики, чтобы избежать staticfiles.E002. +STATIC_ROOT = str(PUBLIC_ROOT / 'static_collected') + +# Базовый URL сайта нужен для абсолютных URL в sitemap.xml. +SITE_BASE_URL = env('SITE_BASE_URL', default='https://oknardia.ru').rstrip('/') +# Файлы sitemap храним в media-volume, чтобы переживали пересоздание контейнера. +SITEMAP_SUBDIR = env('SITEMAP_SUBDIR', default='_serv_sitemap').strip('/ ') +SITEMAP_ROOT = str(Path(MEDIA_ROOT) / SITEMAP_SUBDIR) +SITEMAP_URL_PREFIX = f"{MEDIA_URL.rstrip('/')}/{SITEMAP_SUBDIR}" +SITEMAP_INDEX_URL = f"{SITE_BASE_URL}{SITEMAP_URL_PREFIX}/sitemap.xml" + +# Каталоги, откуда Django читает исходную статику в DEBUG-режиме. +STATICFILES_DIRS = [ + str(STATIC_SOURCE_ROOT) +] if STATIC_SOURCE_ROOT.is_dir() else [] + +# Путь к каталогу static для генерации кэш-файлов и служебных JS. +STATIC_BASE_PATH = str(STATIC_SOURCE_ROOT) + +database_engine = env('DATABASE_ENGINE', default='django.db.backends.sqlite3') +if database_engine == 'django.db.backends.sqlite3': + # Для SQLite принимаем только имя файла из env и кладем БД в PROJECT_ROOT/database. + sqlite_db_filename = Path(env('DATABASE_NAME', default='oknadria.sqlite3')).name + sqlite_db_path = PROJECT_ROOT / 'database' / sqlite_db_filename DATABASES = { 'default': { - 'ENGINE': "django.db.backends.mysql", - 'HOST': MY_DATABASE_HOST_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_DATABASE_HOST_DEV2, - 'PORT': MY_DATABASE_PORT_DEV, # Set to "" for default. Not used with sqlite3. - 'NAME': MY_DATABASE_NAME_DEV, # Not used with sqlite3. - 'USER': MY_DATABASE_USER_DEV, # Not used with sqlite3. - 'PASSWORD': MY_DATABASE_PASSWORD_DEV, # Not used with sqlite3. - # 'OPTIONS': { 'autocommit': True, } + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': str(sqlite_db_path), } } - TOUCH_RELOAD = MY_TOUCH_RELOAD_DEV1 if socket.gethostname() == MY_HOST_HOME1 else MY_TOUCH_RELOAD_DEV2 else: - MEDIA_ROOT = MY_MEDIA_ROOT_PROD - # STATICFILES_DIRS = [MY_STATIC_ROOT_PROD1, ] - STATIC_ROOT = MY_STATIC_ROOT_PROD - SITEMAP_ROOT = MY_SITEMAP_ROOT_PROD - # путь к каталогу static (в эту переменную использовать для указания пути где будут делаться кэш-блоки для шаблонов) - STATIC_BASE_PATH = MY_STATIC_BASE_PATH_PROD DATABASES = { 'default': { - 'ENGINE': "django.db.backends.mysql", - 'HOST': MY_DATABASE_HOST_PROD, # Set to "" for localhost. Not used with sqlite3. - 'PORT': MY_DATABASE_PORT_PROD, # Set to "" for default. Not used with sqlite3. - 'NAME': MY_DATABASE_NAME_PROD, # Not used with sqlite3. - 'USER': MY_DATABASE_USER_PROD, # Not used with sqlite3. - 'PASSWORD': MY_DATABASE_PASSWORD_PROD, # Not used with sqlite3. - # 'OPTIONS': { 'autocommit': True, } + 'ENGINE': database_engine, + 'HOST': env('DATABASE_HOST', default='localhost'), + 'PORT': env('DATABASE_PORT', default='3306'), + 'NAME': env('DATABASE_NAME', default=''), + 'USER': env('DATABASE_USER', default=''), + 'PASSWORD': env('DATABASE_PASSWORD', default=''), } } - TOUCH_RELOAD = MY_TOUCH_RELOAD_PROD + ######################################### # настройки для почтового сервера (они одинаковые для DEV и PROD) -EMAIL_HOST = MY_EMAIL_HOST_DEV -EMAIL_PORT = MY_EMAIL_PORT_DEV -EMAIL_HOST_USER = MY_EMAIL_HOST_USER_DEV -EMAIL_HOST_PASSWORD = MY_EMAIL_HOST_PASSWORD_DEV -SERVER_EMAIL = DEFAULT_FROM_EMAIL = EMAIL_HOST_USER -EMAIL_USE_TLS = True +EMAIL_BACKEND = env( + 'EMAIL_BACKEND', + default='django.core.mail.backends.smtp.EmailBackend', +) +EMAIL_HOST = env('EMAIL_HOST', default='localhost') +EMAIL_PORT = env.int('EMAIL_PORT', default=25) +EMAIL_HOST_USER = env('EMAIL_HOST_USER', default='') +EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD', default='') +EMAIL_USE_TLS = env.bool('EMAIL_USE_TLS', default=True) +EMAIL_USE_SSL = env.bool('EMAIL_USE_SSL', default=False) +DEFAULT_FROM_EMAIL = env('DEFAULT_FROM_EMAIL', default=EMAIL_HOST_USER) +SERVER_EMAIL = env('SERVER_EMAIL', default=DEFAULT_FROM_EMAIL) EMAIL_SUBJECT_PREFIX = 'OKNARDIA ERR: ' # префикс для оповещений об ошибках и необработанных исключениях +SECURE_SSL_REDIRECT = env.bool('SECURE_SSL_REDIRECT', default=False) +SESSION_COOKIE_SECURE = env.bool('SESSION_COOKIE_SECURE', default=False) +CSRF_COOKIE_SECURE = env.bool('CSRF_COOKIE_SECURE', default=False) + # Default primary key field type # https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field @@ -177,10 +211,17 @@ EMAIL_SUBJECT_PREFIX = 'OKNARDIA ERR: ' # префикс для оповещ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' # ключи для Google Captha -CAPTCHA_PUBLIC_KEY = MY_CAPTCHA_PUBLIC_KEY -CAPTCHA_PRIVATE_KEY = MY_CAPTCHA_PRIVATE_KEY +CAPTCHA_PUBLIC_KEY = env('CAPTCHA_PUBLIC_KEY', default='') +CAPTCHA_PRIVATE_KEY = env('CAPTCHA_PRIVATE_KEY', default='') -# количество коммерческих предложений во фреме отчета +# МАГИЧЕСКИЕ ЧИСЛА +# если непонятно какая серия выбрана через каталог (finger fix) выбираем серию типового строения: +DEFAULT_SERIA_ID_FOR_CATALOG = 843 # СЕРИЯ 1-515/9 -- дом в котором я живу +DEFAULT_WIN_WIDTH_MM = 670 # Ширина типового окна для ID=16 (если не выбрано) +DEFAULT_WIN_HEIGHT_MM = 2160 # Высота типового окна для ID=16 (если не выбрано) +DEFAULT_WIN_ID = 16 # ID типового окна (если не выбрано) + +# количество коммерческих предложений во фрейме отчета OFFER_PER_FRAME = 5 OFFER_PER_FRAME_FOR_ONE_FLAP = 10 # папка для хранения изображений @@ -272,4 +313,4 @@ CATALOG_SORTER_MAGIC_NUMBER_TIZER = 1 MAX_LEN_RING_LOG_BUFFER = 250 # МАКСИМАЛЬНЫЙ РАЗМЕР КОЛЬЦЕВОГО БУФЕРА -YANDEX_MAPS_API_KEY = MY_YANDEX_MAPS_API_KEY +YANDEX_MAPS_API_KEY = env('YANDEX_MAPS_API_KEY', default='') diff --git a/oknardia/oknardia/urls.py b/oknardia/oknardia/urls.py index f3f4a97..08b6318 100644 --- a/oknardia/oknardia/urls.py +++ b/oknardia/oknardia/urls.py @@ -15,14 +15,14 @@ 2. Добавьте URL-адрес в urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path, re_path +from django.urls import include, path, re_path from django.conf.urls.static import static from oknardia.settings import * -from web import views, autocomplete_addr, user_manager, blog, diagrams, report1, report2, catalog, prices, service - +from web import views, autocomplete_addr, user_manager, blog, diagrams, report1, report2, catalog, prices, service, \ + catalog_profiles, catalog_series, catalog_openings, catalog_companies urlpatterns = [ - path('admin/', admin.site.urls), + path(ADMIN_URL, admin.site.urls), # главная страница re_path(r'^$', views.main_init), @@ -56,56 +56,64 @@ urlpatterns = [ re_path(r'^stat/series/geo[/*]$', diagrams.statistic_menu), # дубль для старых ссылок re_path(r'^stat/rating[/*]$', report2.ratings), re_path(r'^stat/rating/profiles_rank[/*]$', report2.profiles_rating), - # --- Каталог - # --- --- Каталог профилей - re_path(r'^catalog[/*]$', catalog.catalog_root), - re_path(r'^catalog/profile[/*]$', catalog.catalog_profile), + # --- КАТАЛОГ + re_path(r'^catalog[/*]$', catalog.catalog_root), # ГЛАВНАЯ СТРАНИЦА КАТАЛОГА + # --- --- КАТАЛОГ ПРОФИЛЕЙ + re_path(r'^catalog/profile[/*]$', catalog_profiles.catalog_profile), # СПИСОК ВСЕХ ПРОФИЛЕЙ И ПРОИЗВОДИТЕЛЕЙ re_path(r'^catalog/profile/(?P\d+)-(?P\S*)' - r'/(?P\d+)-(?P\S*)[/*]$', catalog.catalog_profile_model), + r'/(?P\d+)-(?P\S*)[/*]$', + catalog_profiles.catalog_profile_model), # СТРАНИЦА ОПИСАНИЯ МОДЕЛИ ПРОФИЛЯ re_path(r'^catalog/profile/(?P\d+)-(?P\S*)[/*]$', - catalog.catalog_profile_manufacture), - # --- --- Каталог серий типового строительства - re_path(r'^catalog/seria[/*]$', catalog.catalog_seria), - re_path(r'^catalog/seria/(?P[^/]*)/all(?P\d+)[/*]$', catalog.catalog_seria_info), + catalog_profiles.catalog_profile_manufacture), # КАРТОЧКА ОПИСАНИЯ ПРОИЗВОДИТЕЛЯ ПРОФИЛЯ + # --- --- КАТАЛОГ СЕРИЙ ТИПОВОГО СТРОИТЕЛЬСТВА + re_path(r'^catalog/seria[/*]$', catalog_series.catalog_seria), # СПИСОК ВСЕХ СЕРИЙ ЗДАНИЙ + re_path(r'^catalog/seria/(?P[^/]*)/all(?P\d+)[/*]$', + catalog_series.catalog_seria_info), # КАРТОЧКА СЕРИИ ДОМА И ЕЕ СТАТИСТИКА re_path(r'^seria_[^/]*/all(?P\d+)/\S*$', catalog.report_all_info_seria_redirect), # для старых ссылок - # --- --- Каталог стандартных проёмов и схем открывания длч типовых серий строительства - re_path(r'^catalog/standard_opening[/*]$', catalog.standard_opening), - # --- --- Каталог производителей окон - re_path(r'^catalog/company[/*]$', catalog.catalog_company), - re_path(r'^catalog/company/(?P\d+)-(?P\S*)[/*]$', catalog.catalog_company_detail), + # --- --- КАТАЛОГ СТАНДАРТНЫХ ПРОЁМОВ И СХЕМ ОТКРЫВАНИЯ ДЛЧ ТИПОВЫХ СЕРИЙ СТРОИТЕЛЬСТВА + re_path(r'^catalog/standard_opening[/*]$', catalog_openings.standard_opening), # СТРАНИЦА С ТАБЛИЦЕЙ ПРОЁМОМ + # --- --- КАТАЛОГ ПРОИЗВОДИТЕЛЕЙ ОКОН + re_path(r'^catalog/company[/*]$', catalog_companies.catalog_company), # СПИСОК ВСЕХ ПРОИЗВОДИТЕЛЕЙ ОКОН + re_path(r'^catalog/company/(?P\d+)-(?P\S*)[/*]$', + catalog_companies.catalog_company_detail), # КАРТОЧКА ПРОИЗВОДИТЕЛЯ-УСТАНОВЩИКА ОКОН + # --- --- КАТАЛОГ ОКОННЫХ НАБОРОВ (SetKit) — список комплектаций с переходом к сравнению + re_path(r'^catalog/sets[/*]$', catalog.catalog_sets), # ЦЕНОВЫЕ ПРЕДЛОЖЕНИЯ - # --- Одиночное окно + # --- ОДИНОЧНОЕ ОКНО + re_path(r'^catalog/standard_opening/price-(?P\d+)x(?P\d+)mm-tip(?P\d+)[/*]$', + prices.report_one_win_price), # КАНОНИЧЕСКИЙ SEO-URL СТРАНИЦЫ ЦЕН ДЛЯ ОДНОГО ПРОЕМА re_path(r'^tsena-odnogo-okna/(?P\d+)x(?P\d+)mm/tip(?P\d+)[/*]$', - prices.report_one_win_price), - re_path(r'^next_price_one_flap_frame/idW(?P\d+)N(?P\d+)\S*$', prices.next_one_win_price), - # --- Ценовая выдача - re_path(r'^(?P\d+)/(?P\d+)/(?P[\s\S]*)$', prices.report_price), - # --- Подгружаемый фрейм ценовая выдачи + prices.redirect_one_win_price_legacy), # LEGACY-URL: 301 -> КАНОНИЧЕСКИЙ ПУТЬ + re_path(r'^next_price_one_flap_frame/idW(?P\d+)N(?P\d+)\S*$', + prices.next_one_win_price), # ПОДГРУЖАЕМЫЙ ФРЕЙМ С ЦЕНОВЫМИ ПРЕДЛОЖЕНИЯМИ ДЛЯ ОДНОГО ПРОЕМА + # --- ЦЕНОВАЯ ВЫДАЧА (НОВЫЙ РОУТИНГ) + # НОВЫЙ КРАСИВЫЙ URL С ПРЕФИКСАМИ SERIAID, APPARTAD, ADDRESSID + re_path(r'^price/seriaID(?P\d+)--(?P[^/]+)/appartID(?P\d+)/addressID(?P\d+)--(?P[^/]+)/?$', prices.report_price_new), + # --- ПОДГРУЖАЕМЫЙ ФРЕЙМ ЦЕНОВОЙ ВЫДАЧИ (ОСТАВЛЯЕМ СТАРЫЙ) re_path(r'^next_price_frame/idA(?P\d+)MDPO(?P\d+)LON(?P\d+)' r'LAT(?P\d+\.*\d*)N(?P\d+\.*\d*)\S*[/*]$', prices.next_price_frame), + # --- СТАРЫЙ URL ЦЕНОВОЙ ВЫДАЧИ (ДОБАВИМ РЕДИРЕКТ) ДЛЯ ПОИСКОВИКОВ + # --- НЕ УДАЛЯТЬ! КАРТА С СЕРИЯМИ ДОМОВ ИСПОЛЬЗУЕТ ЭТОТ РОУТИНГ, Т.К. ТАКИЕ URL КОРОЧЕ И ДЕЛАЮТ JS КОПАКТНЕЕ + re_path(r'^(?P\d+)/(?P\d+)/(?P[\s\S]*)$', prices.report_price_legacy_redirect), # СРАВНЕНИЕ ОКОННЫХ НАБОРОВ re_path(r'^compare_sets/(?P[\s\S]+|.*)$', report1.compare_offers), # дубль для старых ссылок re_path(r'^compare_offers/(?P[\s\S]+|.*)$', report1.compare_offers), re_path(r'^specification_set/\d$', views.main_init), # заглушка (позже будет спецификация оконного набора) # отображение всех составлющих рейтинга re_path( r'^show_rating_components/(?P\d+)$', report1.show_rating_components), - # СЛУЖЕБНЫЕ СТРАНИЦЫ (для администратора) - # --- страничка "главная сервис-утилит" - re_path(r'^service[/*]$', service.service), - # --- страничка для тестирования верстки текста в блоге - re_path(r'^service/tmp[/*]$', service.tmp), - # --- страничка "нет доступа" - re_path(r'^service/not-denice[/*]$', service.not_denice), - # --- создание файлов sitemap.xml - re_path(r'^service/make_sitemaps[/*]$', service.make_site_maps), ] -if DEBUG: - urlpatterns += static(MEDIA_URL, document_root=MEDIA_ROOT) -# ___ ____ _ _____ _ _ _____ _ -# | | | | \ ___| |_ _ _ ___ |_ _|___ ___| | |_ ___ ___ | _ |___ ___ ___| | -# |_ | | | | -_| . | | | . | | | | . | . | | . | .'| _| | __| .'| | -_| | -# |_| |____/|___|___|___|_ | |_| |___|___|_|___|__,|_| |__| |__,|_|_|___|_| -# |___| +if DEBUG: + # Медиа-файлы + urlpatterns += static(MEDIA_URL, document_root=MEDIA_ROOT) + # --- страничка для тестирования верстки текста в блоге + urlpatterns += [re_path(r'^blog/tmp[/*]$', service.tmp),] + # ___ ____ _ _____ _ _ _____ _ + # | | | | \ ___| |_ _ _ ___ |_ _|___ ___| | |_ ___ ___ | _ |___ ___ ___| | + # |_ | | | | -_| . | | | . | | | | . | . | | . | .'| _| | __| .'| | -_| | + # |_| |____/|___|___|___|_ | |_| |___|___|_|___|__,|_| |__| |__,|_|_|___|_| + # |___| + urlpatterns = [path('__debug__/', include('debug_toolbar.urls')), *urlpatterns] + diff --git a/oknardia/templates/base.html b/oknardia/templates/base.html index c3fd2b9..f58823b 100755 --- a/oknardia/templates/base.html +++ b/oknardia/templates/base.html @@ -4,25 +4,29 @@ - - - + + + - - + + {% block Title %}{% endblock %} : ОКНАРДИЯ - + + + + {# #} {# #} {% block Top_CSS1 %}{% endblock %}{% block Top_CSS2 %}{% endblock %}{% block Top_CSS3 %}{% endblock %} {# #} {# #}{% block Top_JS1 %}{% endblock %}{% block Top_JS2 %}{% endblock %}{% block Top_JS3 %}{% endblock %}{% block Top_JS4 %}{% endblock %}{% block Top_JS5 %}{% endblock %}{% block Top_Meta1 %}{% endblock %} - + {# Аналитика: Google Analytics 4, Yandex.Metrika, Top.Mail.Ru #} + {# Модуль авторизации: управление dropdown меню логина/логаута #}{% block ADD_TO_HEAD %}{% endblock %} @@ -48,13 +52,13 @@
  • Статистика
  • Контакты
  • -
  • Сотрудничество
  • +
  • Сотрудничество
  • Услуги и тарифы
  • - + {% endblock %} @@ -65,25 +69,10 @@ {% block Bottom_Nav_Bar %} {% endblock %} + +{% endblock %} {# ######################################## Нижнее меню-футер КОНЕЦ ######################################## #} {# Модальное окно SOCIAL LOGIN НАЧАЛО #} diff --git a/oknardia/templates/blog/blog_list.html b/oknardia/templates/blog/blog_list.html index 9df47c3..95529f7 100755 --- a/oknardia/templates/blog/blog_list.html +++ b/oknardia/templates/blog/blog_list.html @@ -1,20 +1,121 @@ {% extends "base.html" %}{% load static %} -{% block Title %}Блоги: Стр.{{ PAGE_BACK|add:"1" }}{% endblock %} +{% block Title %}Блог Окнардии для компаний-поставщиков окон и их клиентов — Страница {{ PAGE_BACK|add:"1" }}{% endblock %} {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Description %}Блоги «Окнардия» :: {% for i1 in DIM_BLOGPOST %}{{ i1.HEADER_D }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endblock %} +{% block Description %}Блог Окнардии для компаний-поставщиков окон и их клиентов: публикации о пластиковых окнах, продвижении услуг замены окон, ценах и трендах — Страница {{ PAGE_BACK|add:"1" }}{% endblock %} -{% block Keywords %}oknardia, окнардия, blogs, блоги, публикации, цены пластиковых окон, стоимость пластиковых окон, скидки на пластиковые окна, предложения пластиковых окон, {{ META_KEYWORDS|default:"" }} {% endblock %} +{% block Keywords %}{{ META_KEYWORDS }}{% endblock %} -{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} +{% block Date4Meta %}{% if META_DATA_PUB %}{{ META_DATA_PUB|date:"Y-m-d" }}{% else %}{% now "c" %}{% endif %}{% endblock %} -{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} +{% block Last4Meta %}{% if META_DATA_MODIFY %}{{ META_DATA_MODIFY|date:"Y-m-d" }}{% else %}{% now "c" %}{% endif %}{% endblock %} -{% block Author4Meta %}: Блоги{% endblock %} +{% block Author4Meta %}Окнардия{% endblock %} -{% block CopyrightAuthor4Meta %}: Блоги{% endblock %} +{% block CopyrightAuthor4Meta %}Окнардия{% endblock %} + +{% block Top_Meta1 %}{# #} + + {% if PAGE_BACK > 0 %}{% endif %} + {% if FORW_BUTTON %}{% endif %} + {# #} + + + + + + + {% if META_IMAGE %}{% else %}{% endif %} + + + + + {% if META_IMAGE %}{% else %}{% endif %} +{# #}{% endblock %} + +{% block ADD_TO_HEAD %}{# #} + +{# #}{% endblock %} {% block Top_JS3%} {% endblock %} +{% block ADD_TO_HEAD %}{# #} + +{# #}{% endblock %} + {% block Main_Content %}
    {% if not IS_ARCHIVE %} @@ -78,7 +124,7 @@
    {# Листалка: НАЧАЛО #}
    -
    +
    +
    {# Листалка: КОНЕЦ #}  {# --- Баннер: НАЧАЛО --- #}

    {% include "ad/bannet-wide.html" %}
    @@ -102,5 +148,4 @@ {% block Top_Nav_Bar %} {# ОТЛАДКА, ГАСИМ ВЕРХНЕЕ МЕНЮ #} {% endblock %} -{% endcomment %} - +{% endcomment %} \ No newline at end of file diff --git a/oknardia/templates/catalog/catalog_company.html b/oknardia/templates/catalog/catalog_company.html index 42caf0d..b3adf62 100755 --- a/oknardia/templates/catalog/catalog_company.html +++ b/oknardia/templates/catalog/catalog_company.html @@ -1,58 +1,81 @@ {% extends "base.html" %} {% load static %}{% load filters %} -{% block Title %}Каталог изготовителей и поставщиков окон{% endblock %} +{% block Title %}Каталог оконных компаний: производители и поставщики окон, рейтинг и цены{% endblock %} {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Description %}Каталог изготовителей окон, партнёры «Окнардия», рейтинг, {% for i in COMPANIES %}{{ i.sMerchantName }}, {% endfor %} средняя цена окна{% endblock %} +{% block Description %}Актуальный каталог оконных компаний России. Сравните производителей и поставщиков пластиковых окон по рейтингу, ассортименту, средней цене и дате последнего обновления.{% endblock %} -{% block Keywords %}Оконные компании, {% for i in COMPANIES %}{{ i.sMerchantName }}, {% endfor %} изготовители окон, производители окон, постащики окон, партнёры, каталог компаний, каталог оконных компаний, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %} +{% block Keywords %}оконные компании, каталог компаний, производители окон, поставщики окон, рейтинг оконных компаний, сравнить цены на окна, oknardia, окнардия{% endblock %} -{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} +{% block Author4Meta %}: Каталог «Окнардия»{% endblock %} -{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} - -{% block Author4Meta %}: Каталог изготовителей окон{% endblock %} - -{% block CopyrightAuthor4Meta %}: Каталог изготовителей окон{% endblock %} +{% block CopyrightAuthor4Meta %}: Каталог «Окнардия»{% endblock %} {% block Top_Meta1 %}{# #} - {% if IMG_FOR_BLOG %} - {% else %} - {% endif %} - - - - - - - - + - - - - - + - - - - + + + + - - + + - - - + {# Удалить: — устаревший тег #} + + {# #}{% endblock %} +{% block ADD_TO_HEAD %}{% comment %} +JSON-LD для страницы-списка компаний: CollectionPage + ItemList с элементами Organization. +Это понятнее для поисковиков, чем legacy microdata на метатегах. +{% endcomment %} + +{% endblock %} + + {% block Main_Content %}
    {# #}
    @@ -90,7 +113,3 @@ {% include "report/report_log_user_visit.html" %}
    {% endblock %} - - - - diff --git a/oknardia/templates/catalog/catalog_company_detail.html b/oknardia/templates/catalog/catalog_company_detail.html index 03b251b..2044442 100755 --- a/oknardia/templates/catalog/catalog_company_detail.html +++ b/oknardia/templates/catalog/catalog_company_detail.html @@ -5,30 +5,20 @@ {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Description %}«{{ COMPANY }}», описание компании «{{ COMPANY }}», оконные наборы от «{{ COMPANY }}» и их состав, характеристики «{{ COMPANY }}», рейтинг «{{ COMPANY }}», средние цены и отклонение цен «{{ COMPANY }}».{% endblock %} +{% block Description %}Производитель окон «{{ COMPANY }}» в каталоге Окнардии: оконные наборы, их состав и характеристики, независимый рейтинг качества, средние цены на замену оконных конструкций в типовых домах.{% endblock %} -{% block Keywords %}{{ COMPANY }}, компания {{ COMPANY }}, окна {{ COMPANY }}, изготовитель окон {{ COMPANY }}, производитель окон {{ COMPANY }}, поставщик окон {{ COMPANY }}, партнёр, каталог компаний, каталог оконных компаний, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %} +{% block Keywords %}{{ COMPANY }}, компания {{ COMPANY }}, окна {{ COMPANY }}, изготовитель окон {{ COMPANY }}, производитель окон {{ COMPANY }}, поставщик окон {{ COMPANY }}, партнёр, каталог компаний, каталог оконных компаний, oknardia, окнардия{% endblock %} -{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} -{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} +{% block Author4Meta %}Каталог изготовителей окон{% endblock %} -{% block Author4Meta %}: Каталог изготовителей окон{% endblock %} - -{% block CopyrightAuthor4Meta %}: Каталог изготовителей окон{% endblock %} +{% block CopyrightAuthor4Meta %}Каталог изготовителей окон{% endblock %} {% block Top_Meta1 %}{# #} - {% if IMG_FOR_BLOG %} - {% else %} - {% endif %} - - - - - + {# Microdata (itemprop) убрана — заменена на JSON-LD в блоке ADD_TO_HEAD ниже (чище, надёжнее) #} - - + + {# Удалить: — тег Google News 2011 г., отменён в 2014, поисковики игнорируют #} @@ -36,24 +26,60 @@ - + - - - + + {# Нельзя вкладывать {{ }} внутрь аргумента фильтра |default — используем {% if %}{% else %} #} + + - - + + - - - + {# Удалить: — устарело с 2015, Twitter его не использует #} + + {# #}{% endblock %} +{% block Top_JS5 %} + {% endblock %} -{% block Top_JS5 %}{% endblock %} +{% block ADD_TO_HEAD %}{% comment %} + JSON-LD разметка Schema.org для страницы производителя окон. + Тип LocalBusiness описывает компанию-поставщика окон: название, контакты, адрес, геокоординаты, + логотип и ссылку на официальный сайт производителя. + Данные берутся из первого набора в SETS (все наборы принадлежат одному офису/бренду), + поэтому достаточно SETS.0 для контактной информации. + Документация: https://schema.org/LocalBusiness #}{% endcomment %} + +{% endblock %} {% block Main_Content %} @@ -112,7 +138,14 @@ {# ПРАВАЯ КОЛОНКА: НАЧАЛО #}
    - +

    Оконный набор: «{{ i.sSetName|safe }}»

    +

    + Оконный набор: «{{ i.sSetName|safe }}» + + в каталоге наборов + +

    +
    {% for Star in i.fSetRating.STARS %}{% if Star == 0 %}{% else %}{% endif %}{% endfor %} {% if i.fSetRating.RATING > -0.01 %} {{ i.fSetRating.RATING|stringformat:".2f" }}{% endif %}
    diff --git a/oknardia/templates/catalog/catalog_of_profiles.html b/oknardia/templates/catalog/catalog_of_profiles.html index fcb83d6..e187032 100755 --- a/oknardia/templates/catalog/catalog_of_profiles.html +++ b/oknardia/templates/catalog/catalog_of_profiles.html @@ -5,18 +5,70 @@ {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Description %}Каталог оконных профилей{% endblock %} +{% block Description %}Подберите оконный профиль под свои требования: в каталоге «Окнардии» собраны производители, марки и ключевые характеристики.{% endblock %} -{% block Keywords %}каталог оконных профилей, каталог производителей оконных профилей, каталог профилей, оконные профили, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %} - -{% block Date4Meta %}{{ CATALOG_LAST_UPDATE|date:"c" }}{% endblock %} - -{% block Last4Meta %}{{ CATALOG_LAST_UPDATE|date:"c" }}{% endblock %} +{% block Keywords %}оконные профили, каталог профилей, сравнение профилей, производители оконных профилей, характеристики оконных профилей, oknardia {{ META_KEYWORDS|default:"" }} {% endblock %} {% block Author4Meta %}: Каталог{% endblock %} {% block CopyrightAuthor4Meta %}: Каталог{% endblock %} +{% block Top_Meta1 %}{# #} + + + + + + + + + + + + + + + + +{# #}{% endblock %} + +{% block ADD_TO_HEAD %} + + {% endblock %} + {% block Main_Content %}
    {# #}
    @@ -27,7 +79,7 @@
  • Оконные профили
  • Каталог оконных профилей

    -

    Узнать о производителях, познакомиться с детальными характеристики и описаниями оконных профилей можно кликнув по ссылкам. Сейчас в каталоге «Окнардии» представлено {{ CATALOG_MANUFACT_NUM_W }} профилей ({{ CATALOG_PROFILE_NUM }} в базе). Последнее обновление {{ CATALOG_LAST_UPDATE_W }}.

    +

    Узнать о производителях, познакомиться с детальными характеристики и описаниями оконных профилей можно кликнув по ссылкам. Сейчас в каталоге «Окнардии» представлено {{ CATALOG_MANUFACT_NUM_W }} профилей ({{ CATALOG_PROFILE_NUM }} в базе).

    {# #}
    @@ -61,4 +113,3 @@ {# ОТЛАДКА, ГАСИМ ВЕРХНЕЕ МЕНЮ #} {% endblock %} {% endcomment %} - diff --git a/oknardia/templates/catalog/catalog_of_profiles_manufacture.html b/oknardia/templates/catalog/catalog_of_profiles_manufacture.html index 443d700..a276ef8 100755 --- a/oknardia/templates/catalog/catalog_of_profiles_manufacture.html +++ b/oknardia/templates/catalog/catalog_of_profiles_manufacture.html @@ -9,48 +9,35 @@ {% block Keywords %}{{ CATALOG_MANUFACT }}, оконные профили {{ CATALOG_MANUFACT }}, производитель {{ CATALOG_MANUFACT }}, {% for i in PROFILES %}{{ i.PROFILE_NAME }}, {% endfor %}каталог оконных профилей, каталог производителей оконных профилей, каталог профилей, оконные профили, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %} -{% block Date4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %} - -{% block Last4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %} - {% block Author4Meta %}: Каталог{% endblock %} {% block CopyrightAuthor4Meta %}: Каталог{% endblock %} -{% block Top_Meta1 %} - - {% if IMG_FOR_BLOG %} - {% else %} - {% endif %} - - - - - - - - - +{% block Top_Meta1 %}{# #} + {# Удалить: itemprop microdata и rel=standout в head (устаревшее), используем JSON-LD ниже #} + {# Удалить: twitter:domain (устаревшее поле) #} + + - + - - - - - - - - + + + + + + + - - - {% endblock %} + + + +{# #}{% endblock %} {% block Top_JS4 %} @@ -79,6 +66,73 @@ } {% endblock %} +{% block ADD_TO_HEAD %} + + + {% endblock %} + {% block Main_Content %}
    {# #}
    @@ -105,7 +159,9 @@ {% endfor %} -

    Сравнить компонеты рейтинга профилей можно в разделе Ретинги.

    {% if not OFFERS_BY_MAUFACTURE == 0 %} +

    Сравнить компонеты рейтинга профилей можно в разделе Ретинги.
    + Методика расчёта: «Рейтинг Окнардии и как он устроен».

    {% if not OFFERS_BY_MAUFACTURE == 0 %}

    Доля предложений окон на основе профилей {{ CATALOG_MANUFACT }} в базе «Окнардия»

    Партнёры «Окнардия» использующие профили производства {{ CATALOG_MANUFACT }} в своих предложениях:
    diff --git a/oknardia/templates/catalog/catalog_of_profiles_model.html b/oknardia/templates/catalog/catalog_of_profiles_model.html index 7a5736d..9cc3614 100755 --- a/oknardia/templates/catalog/catalog_of_profiles_model.html +++ b/oknardia/templates/catalog/catalog_of_profiles_model.html @@ -5,31 +5,17 @@ {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Description %}Характеристики оконного профиля {{ CATALOG_MODEL.sProfileName }} производства {{ CATALOG_MODEL.sProfileManufacturer }}{% endblock %} +{% block Description %}Оконный профиль {{ CATALOG_MODEL.sProfileName }} от {{ CATALOG_MODEL.sProfileManufacturer }}: характеристики, рейтинг, комплектация и применение в оконных предложениях партнёров Окнардии.{% endblock %} {% block Keywords %}оконный профиль {{ CATALOG_MODEL.sProfileName }}, характеристики профиля {{ CATALOG_MODEL.sProfileName }}, описание профиля {{ CATALOG_MODEL.sProfileName }}, производитель оконный профилей {{ CATALOG_MODEL.sProfileManufacturer }}, каталог оконных профилей, каталог производителей оконных профилей, каталог профилей, оконные профили, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %} -{% block Date4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %} - -{% block Last4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %} - {% block Author4Meta %}: Каталог{% endblock %} {% block CopyrightAuthor4Meta %}: Каталог{% endblock %} -{% block Top_Meta1 %} - - {% if IMG_FOR_BLOG %} - {% else %} - {% endif %} - - - - - - - - +{% block Top_Meta1 %}{# #} + + @@ -37,20 +23,100 @@ - - - - - - + + + + + + - - - + + + - - - {% endblock %} + + + +{# #}{% endblock %} + +{% block ADD_TO_HEAD %} + {# JSON-LD для карточки оконного профиля и хлебных крошек #} + +{% endblock %} {% block Main_Content %}
    @@ -125,7 +191,12 @@ {% if CATALOG_MODEL.sProfileColor == "" %}—{% else %}{{ CATALOG_MODEL.sProfileColor|capfirst }}{% endif %} - {% if LIST_OTHER|length > 1 %} + {% if CATALOG_MODEL.fProfileRating > -0.1 %} +

    Рейтинг модели рассчитан алгоритмом «Окнардии» по статистическому ранжированию + характеристик (метод Манна-Уитни){% if PROFILE_RATING_SAMPLE_SIZE > 0 %} на выборке из + {{ PROFILE_RATING_SAMPLE_SIZE }} моделей профилей{% endif %}. Методика расчёта: + «Рейтинг Окнардии и как он устроен».

    {% endif %}{% if LIST_OTHER|length > 1 %}

    Прочие характеристики профиля:

      {% for LI_BULL in LIST_OTHER %}
    • {{ LI_BULL|safe }}
    • {% endfor %} diff --git a/oknardia/templates/catalog/catalog_root.html b/oknardia/templates/catalog/catalog_root.html index 0ab13b5..fbb1519 100755 --- a/oknardia/templates/catalog/catalog_root.html +++ b/oknardia/templates/catalog/catalog_root.html @@ -5,30 +5,18 @@ {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Description %}Каталог «Окнардия»{% endblock %} +{% block Description %}Каталог «Окнардия»: оконные и дверные профили, стеклопакеты, фурнитура, типовые серии домов, стандартные проёмы и партнёры-поставщики окон.{% endblock %} {% block Keywords %}Каталог, каталог оконных профилей, каталог стеклопакетов, каталог фурнитуры, каталог серий домов, каталог оконных проёмов, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %} -{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} - -{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} - {% block Author4Meta %}: Каталог «Окнардия»{% endblock %} {% block CopyrightAuthor4Meta %}: Каталог «Окнардия»{% endblock %} -{% block Top_Meta1 %}{# #} - {% if IMG_FOR_BLOG %} - {% else %} - {% endif %} - - - - - - - - +{% block Top_Meta1 %}{# #} + {# Удалить: itemprop microdata, rel=standout, twitter:domain — устаревшие теги #} + + @@ -36,21 +24,81 @@ - - + + - - - + + + - - - + + + - - - -{# #}{% endblock %} + + + +{# #}{% endblock %} + +{% block ADD_TO_HEAD %} + {# JSON-LD: корневая страница каталога — CollectionPage + BreadcrumbList + структура разделов #} + + +{% endblock %} {% block Main_Content %}
      @@ -66,7 +114,7 @@
      {# ПЕРВЫЙ РАЗДЕЛ С РЕКЛАМОЙ СБОКУ #}
      {# И ЕЩЁ ОДИН РАЗДЕЛ #}

      Оконные и дверные профили

      -

      Каталог систем оконных и дверных профилей и описание компаний-производителей. Каталог содержит детальные характеристики профилей: сопротивление теплопередаче Ro (м²×°C/Вт), коэффициент звукоизоляции (дБ), число камер рамы и створки, тип и армирования, монтажная ширина и другие. Пластиковые (ПВХ), деревянные, комбинированные и другие системы профилей.

      +

      Каталог систем оконных и дверных профилей и описание компаний-производителей. Каталог содержит детальные характеристики профилей: сопротивление теплопередаче Ro (м²×°C/Вт), коэффициент звукоизоляции (дБ), число камер рамы и створки, тип и армирование, монтажная ширина и другие. Пластиковые (ПВХ), деревянные, комбинированные и другие системы профилей.

      {# И ЕЩЁ ОДИН РАЗДЕЛ #}

      Каталог серий домов

      Типовые проекты жилого строительства, вхождение стандартных оконных проёмов и балконных блоков в планировки типовых квартир серии, графики ввода в эксплуатацию зданий серии, география строительства, износ жилого фонда…

      @@ -76,8 +124,10 @@

      Размеры и рекомендованные схемы открывания стандартных проёмов и балконных блоков базы «Окнардия», коммерческие предложения партнёров агрегатора, условия поставки, комплектация, сопутствующие услуги и возможные скидки.

      {# И ОПЯТЬ РАЗДЕЛ С РЕКЛАМОЙ СБОКУ #}
      - {# И ЕЩЁ ОДИН РАЗДЕЛ #}

      Производители и поставщики окон (в разработке)

      -

      Компании-партнеры «Окнардии», контатная информация, условия и скидки, конфигурации и рейтинги их оконных предложений.

      + {# И ЕЩЁ ОДИН РАЗДЕЛ #}

      Производители и поставщики окон

      +

      Компании-партнеры «Окнардии», контактная информация, условия и скидки, конфигурации и рейтинги их оконных предложений.

      + {# И ЕЩЁ ОДИН РАЗДЕЛ #}

      Оконные наборы: характеристики, комплектации и сравнение

      +

      Готовые комплектации окон разных поставщиков: профиль, стеклопакет, фурнитура и монтаж в одном предложении. Сравнивайте предложения компаний устанавливающих окна по характеристикам (теплопередача, звукоизоляция, состав услуг, рейтинг «Окнардии» и многое другое).

      {# ВТОРОЙ РАЗДЕЛ #} {# И ЕЩЁ ОДИН РАЗДЕЛ #}

      Каталог стеклопакетов (в разработке)

      Стеклопакеты и описание компаний-производителей стекла. Каталог содержит детальные характеристики: схемы стеклопакетов, наличие напыления k- и i-микропленок, тип газа-заполнителя, сопротивление теплопередаче Ro (м²×°C/Вт), коэффициент звукоизоляции (дБ), число камер, тонирование…

      @@ -98,5 +148,3 @@ {% include "report/report_log_user_visit.html" %}
      {% endblock %} - - diff --git a/oknardia/templates/catalog/catalog_seria.html b/oknardia/templates/catalog/catalog_seria.html index 91b84a5..5abbf5d 100755 --- a/oknardia/templates/catalog/catalog_seria.html +++ b/oknardia/templates/catalog/catalog_seria.html @@ -5,30 +5,17 @@ {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Description %}Каталог серий зданий и типовое панельное строительство оконного агрегатора Окнардия{% endblock %} +{% block Description %}Каталог типовых серий домов России: панельные и блочные серии, ссылки на подробные страницы серий, их планировки и стандартные оконные проёмы.{% endblock %} -{% block Keywords %}типовое строительство, панельные серии, серии домов, серии зданий, типовые дома, типовые здания, каталог серий типового строительства, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %} - -{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} - -{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} +{% block Keywords %}типовое строительство, панельные серии, серии домов, серии зданий, типовые дома, типовые здания, каталог серий типового строительства, oknardia, окнардия{% endblock %} {% block Author4Meta %}Серии домов : {% endblock %} {% block CopyrightAuthor4Meta %}Cерии домов : {% endblock %} {% block Top_Meta1 %}{# #} - {% if IMG_FOR_BLOG %} - {% else %} - {% endif %} - - - - - - - - + {# Legacy microdata (itemprop/itemscope) удалена: используем JSON-LD в ADD_TO_HEAD #} + @@ -36,23 +23,64 @@ - + - - - - + + + + - + - - - + + + {# #}{% endblock %} +{% block ADD_TO_HEAD %}{% comment %} +JSON-LD для страницы списка типовых серий домов. +CollectionPage + ItemList помогают поисковику трактовать страницу как каталог сущностей. +{% endcomment %} + +{% endblock %} + + {% block Main_Content %}
      {# #}
      diff --git a/oknardia/templates/catalog/catalog_sets.html b/oknardia/templates/catalog/catalog_sets.html new file mode 100644 index 0000000..96e97cf --- /dev/null +++ b/oknardia/templates/catalog/catalog_sets.html @@ -0,0 +1,385 @@ +{% extends "base.html" %} +{% load static %} +{% load filters %} + +{% block Title %}Оконные наборы: характеристики, комплектации и сравнение — каталог «Окнардия»{% endblock %} + +{% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} + +{% block Description %}Каталог оконных наборов «Окнардия»: готовые комплектации для замены окон с профилем, стеклопакетом и монтажом в одном предложении. Подробные характеристики, рейтинг и сравнение от разных поставщиков.{% endblock %} + +{% block Keywords %}оконные наборы, комплектации окон, сравнение окон, профиль и стеклопакет, монтаж окон, окнардия{% endblock %} + +{% block Top_Meta1 %} + + + + + + + + + + + + + +{% endblock %} + +{% block ADD_TO_HEAD %} +{# JSON-LD: CollectionPage каталога наборов — BreadcrumbList + ItemList с кратким описанием каждого Product #} + + +{# CSS для плавающей панели выбора сравнения #} + +{% endblock %} + +{% block Main_Content %} +
      + + {# Хлебные крошки #} +
      +
      + +

      Оконные наборы: характеристики, комплектации и сравнение

      +

      Оконный набор — готовая комплектация для замены окон в вашем доме: профиль, стеклопакет, + фурнитура и монтаж в одном предложении от компаний-партнёров «Окнардии». + Отметьте несколько интересных наборов и сравните их детально по всем характеристикам.

      +
      +
      + + {# Список карточек #} + {% for item in SET_LIST %} +
      + + {# ---- ШАПКА КАРТОЧКИ: название + рейтинг + логотип ---- #} +
      +
      + + {# Название + звёздочки рейтинга #} +
      +

      {{ item.kit.sSetName }}

      +
      + {% for star in item.stars %}{% if star %}{% else %}{% endif %}{% endfor %}{% if item.kit.fSetRating > 0.1 %} {{ item.kit.fSetRating|stringformat:".2f" }}{% endif %} +
      +
      + + {# Логотип компании — кликабельный, ведёт на карточку компании в каталоге #} +
      + {% if item.merchant_logo %} + {% if item.merchant_id %}{% endif %} + {{ item.merchant_name }} + {% if item.merchant_id %}{% endif %} + {% endif %} +
      + +
      +
      {# /panel-heading #} + + {# ---- ТЕЛО КАРТОЧКИ: три колонки — условия | профиль | стеклопакет ---- #} +
      +
      + + {# == Колонка 1: компания и условия поставки == #} +
      +

      Поставщик

      + {% if item.merchant_id %} +

      + + {{ item.merchant_name }} + +

      + {% elif item.merchant_name %} +

      {{ item.merchant_name }}

      + {% endif %} + + + {% if item.kit.sSetImplementAll %} + + {% endif %} + {% if item.kit.sSetImplementHandles %} + + {% endif %} + {% if item.kit.sSetImplementHinges %} + + {% endif %} + {% if item.kit.sSetImplementLatch %} + + {% endif %} + {% if item.kit.sSetImplementLimiter %} + + {% endif %} + {% if item.kit.sSetImplementCatch %} + + {% endif %} + {% if item.kit.sSetClimateControl|length > 3 %} + + {% endif %} + + + + + + + + + + + + + + + + + + + + + {% if item.kit.sSetOtherConditions %} + + {% endif %} +
      Фурнитура:{{ item.kit.sSetImplementAll|capfirst }}
       Ручки:{{ item.kit.sSetImplementHandles|capfirst }}
       Петли:{{ item.kit.sSetImplementHinges|capfirst }}
       Запоры:{{ item.kit.sSetImplementLatch|capfirst }}
       Огранич.:{{ item.kit.sSetImplementLimiter|capfirst }}
       Фиксаторы:{{ item.kit.sSetImplementCatch|capfirst }}
      Климат-конт.:{{ item.kit.sSetClimateControl|capfirst }}
      Подоконник: + {% if item.kit.sSetSill %}{{ item.kit.sSetSill|capfirst }}{% else %}—{% endif %} +
      Водоотлив: + {% if item.kit.sSetPanes %}{{ item.kit.sSetPanes|capfirst }}{% else %}—{% endif %} +
      Откос: + {% if item.kit.sSetSlope %}{{ item.kit.sSetSlope|capfirst }}{% else %}—{% endif %} +
      Доставка: + {{ item.kit.sSetDelivery|capfirst }} +
      Монтаж: + {{ item.kit.sSetUninstallInstall|capfirst }} +
      Прочее:{{ item.kit.sSetOtherConditions|capfirst }}
      +
      {# /col компания #} + + {# == Колонка 2: профиль == #} +
      +

      + Профиль: + {{ item.profile.sProfileName }} + — {{ item.profile.sProfileManufacturer }} +

      + {% if item.profile.sProfileBriefDescription %} +

      {{ item.profile.sProfileBriefDescription }}

      + {% endif %} + + + {% if item.profile.iProfileCameras %}{% endif %} + {% if item.profile.iProfileThickness > 5 %}{% endif %} + {% if item.profile.iProfileGlazingThickness > 4 %}{% endif %} + {% if item.profile.fProfileHeatTransf > 0.1 %}{% endif %} + {% if item.profile.fProfileSoundproofing > 1 %}{% endif %} + {% if item.profile.fProfileSeals > 0 %}{% endif %} + {% if item.profile.iProfileHeight > 15 %}{% endif %} + {% if item.profile.iProfileRabbet > 1 %}{% endif %} + {% if item.profile.sProfileColor %}{% endif %} + {% if item.profile.sProfileReinforcement %}{% endif %} + {% if item.profile.sProfileSealDescription %}{% endif %} + {% if item.profile.sProfileFillet %}{% endif %} + {% if item.profile.sProfileOther %}{% endif %} +
      Производитель:{{ item.profile.sProfileManufacturer }}
      Камер рамы/створки:{{ item.profile.iProfileCameras }} шт.
      Монтажная ширина:{{ item.profile.iProfileThickness }} мм
      Макс. толщина СП:{{ item.profile.iProfileGlazingThickness }} мм
      Теплопередача Ro:{{ item.profile.fProfileHeatTransf }} м²·°C/Вт
      Звукоизоляция:{{ item.profile.fProfileSoundproofing }} дБ
      Контуры уплотнения:{{ item.profile.fProfileSeals }} шт.
      Высота в проёме:{{ item.profile.iProfileHeight }} мм
      Фальц рамы:{{ item.profile.iProfileRabbet }} мм
      Цвет:{{ item.profile.sProfileColor|capfirst }}
      Армирование:{{ item.profile.sProfileReinforcement }}
      Уплотнитель:{{ item.profile.sProfileSealDescription|capfirst }}
      Штапик:{{ item.profile.sProfileFillet }}
      Прочие хар-ки:{{ item.profile.sProfileOther }}
      +
      {# /col профиль #} + + {# == Колонка 3: стеклопакет == #} +
      +

      + Стеклопакет: {{ item.glazing.sGlazingName }} +

      + {% if item.glazing.sGlazingBriefDescription %} +

      {{ item.glazing.sGlazingBriefDescription|capfirst }}

      + {% endif %} + + {% if item.glazing.sGlazingMark and item.glazing.sGlazingMark != "—" %}{% endif %} + {% if item.glazing.sGlazingManufacturer and item.glazing.sGlazingManufacturer != "—//—" and item.glazing.sGlazingManufacturer != "—" %}{% endif %} + {% if item.glazing.iGlazingCamerasN >= 1 %}{% endif %} + {% if item.glazing.iGlazingThickness >= 3 %}{% endif %} + {% if item.glazing.fGlazingHeatTransfer > 0.1 %}{% endif %} + {% if item.glazing.fGlazingSoundproofing >= 10 %}{% endif %} + {% if item.glazing.fGlazingLightTransmission >= 1 %}{% endif %} + {% if item.glazing.fGlazingPassingSun >= 1 %}{% endif %} + {% if item.glazing.sGlazingLightReflectance and item.glazing.sGlazingLightReflectance != "—/—" %}{% endif %} + {% if item.glazing.sGlazingReflectionAndAbsorptionOfHeat and item.glazing.sGlazingReflectionAndAbsorptionOfHeat != "—/—" %}{% endif %} + {% if item.glazing.sGlazingToning %}{% endif %} +
      Схема:{{ item.glazing.sGlazingMark }}
      Производитель:{{ item.glazing.sGlazingManufacturer }}
      Камер:{{ item.glazing.iGlazingCamerasN }} шт.
      Толщина:{{ item.glazing.iGlazingThickness }} мм
      Теплопередача Ro:{{ item.glazing.fGlazingHeatTransfer }} м²·°C/Вт
      Звукоизоляция:{{ item.glazing.fGlazingSoundproofing }} дБ
      Светопропускание:{{ item.glazing.fGlazingLightTransmission }} %
      Солнцепропускание:{{ item.glazing.fGlazingPassingSun }} %
      Светоотражение:{{ item.glazing.sGlazingLightReflectance }} %
      Теплоотражение/погл.:{{ item.glazing.sGlazingReflectionAndAbsorptionOfHeat }} %
      Тонирование:{{ item.glazing.sGlazingToning|capfirst }}
      +
      {# /col стеклопакет #} + +
      {# /row #} +
      {# /panel-body #} + + {# ---- ПОДВАЛ КАРТОЧКИ: чекбокс «отметить» + кнопка сравнения ---- #} + + +
      {# /panel kit-card #} + {% empty %} +
      Нет доступных оконных наборов.
      + {% endfor %} + + {# --- Баннер --- #} +

      {% include "ad/bannet-wide.html" %}
      + +
      + {% include "report/report_last_user_visit.html" %} + {% include "report/report_log_user_visit.html" %} +
      + +
      {# /container-fluid #} + +{% endblock %} + +{% block Top_JS3 %}{% endblock %} + diff --git a/oknardia/templates/catalog/catalog_standard_opening.html b/oknardia/templates/catalog/catalog_standard_opening.html index 65f0314..a881ef4 100755 --- a/oknardia/templates/catalog/catalog_standard_opening.html +++ b/oknardia/templates/catalog/catalog_standard_opening.html @@ -1,33 +1,23 @@ {% extends "base.html" %}{% load static %} -{% block Title %} Стандартные оконные проёмы типовых серий домов :: каталог{% endblock %} +{% block Title %}Стандартные оконные проёмы и балконные блоки для типовых серий домов: размеры, схемы, каталог{% endblock %} {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Description %}Каталог «Окнардия»: стандартные оконные проёмы типовых серий домов...{% endblock %} +{% block Description %}Найдите точные размеры (ширину и высоту) и схемы стандартных оконных проёмов и балконных блоков для самых распространённых типовых серий домов в России. Удобный каталог для подбора окон.{% endblock %} -{% block Keywords %}оконные проёмы, стандартные окна, стандартные оконные проемы, каталог, каталог оконных проёмов, oknardia, окнардия {{ META_KEYWORDS|default:"" }} {% endblock %} +{% block Keywords %}типовые окна, размеры окон, оконные проемы, балконный блок, стандартные окна, размеры окон в панельном доме, серия дома, каталог окон, схемы открывания окон, П-44, II-49, 1-515, oknardia, окнардия{% endblock %} -{% block Date4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %} - -{% block Last4Meta %}{{ PUB_DAT|date:"c" }}{% endblock %} +{# Date4Meta/Last4Meta не переопределяем: используем дефолт из base.html #} {% block Author4Meta %}: Каталог «Окнардия»{% endblock %} {% block CopyrightAuthor4Meta %}: Каталог «Окнардия»{% endblock %} {% block Top_Meta1 %}{# #} - {% if IMG_FOR_BLOG %} - {% else %} - {% endif %} - - - - - + {# Legacy microdata (itemprop/itemscope) удалена: используем JSON-LD в ADD_TO_HEAD #} - - + @@ -35,21 +25,67 @@ - + - - - - + + + + - - + + - - - -{# #}{% endblock %} + + +{# #}{% endblock %} + +{% block ADD_TO_HEAD %}{% comment %} +JSON-LD для страницы-списка типовых оконных проемов. +CollectionPage + ItemList помогают поисковику понять структуру каталога. +{% endcomment %} + +{% endblock %} {% block Main_Content %}
      @@ -58,18 +94,18 @@
      {# #}
      {# ПЕРВЫЙ РАЗДЕЛ #}
      -

      Стандартные оконные проёмы и балконные блоки

      -

      Ценовая выдача «Окнардии» основана на базе стандартных оконных проёмов в типовых сериях домов. Для каждого проёма существуют рекомендованные организациями-проектировщиками схемы открывание, но партнёры «Окнардии» могут предложить свои, более расширенные или наоборот сокращенные. В таблице приведены параметры стандартных проёмов базы.

      +

      Стандартные оконные проёмы и балконные блоки

      +

      Ценовая выдача «Окнардии» основана на базе стандартных оконных проёмов в типовых сериях домов. Для каждого проёма существуют рекоме­ндованные органи­зациями-проекти­ровщиками схемы открывание, но партнёры «Окнардии» могут предложить свои, более расширенные или наоборот сокращенные. В таблице приведены параметры стандартных проёмов базы.

      {# реклама Oknardia 250x250 СБОКУ #}
      {% include "ad/bannet-250x250.html" %}
      - +
      @@ -97,25 +133,16 @@ - -{# {% for j in SERIAS %}#} -{# {% endfor %}#} + {% endfor %}
      Размеры (мм){% if i.IS_DOOR %}да{% else %}—{% endif %} {{ i.DESCRIPTION }} {% for j in i.INCLUDING_IN_SERIA %}{{ j.NAME }}{% if not forloop.last %}, {% endif %}{% endfor %}цены{% if j.id in i.INCLUDING_IN_SERIA %}#{% endif %}цены
      - -
      - - {# --- Баннер: НАЧАЛО --- #} -

      {% include "ad/bannet-wide.html" %}
      - {# --- Баннер: конец --- #} + {# --- Баннер: НАЧАЛО --- #}

      {% include "ad/bannet-wide.html" %}
      {# --- Баннер: конец --- #}
      {% include "report/report_last_user_visit.html" %} {% include "report/report_log_user_visit.html" %}
      -
      {% endblock %} - - +
    {% endblock %} \ No newline at end of file diff --git a/oknardia/templates/contact.html b/oknardia/templates/contact.html index 7cde0c0..c6d81f0 100755 --- a/oknardia/templates/contact.html +++ b/oknardia/templates/contact.html @@ -1,16 +1,20 @@ {% extends "base.html" %}{% load static %} -{% block Title %}Контакты{% endblock %} +{% block Title %}Контакты маркетплейса Окнардия | Адрес, телефон, email для связи{% endblock %} {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} +{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"Y-m-d" }}{% else %}{% now "c" %}{% endif %}{% endblock %} -{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} +{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"Y-m-d" }}{% else %}{% now "c" %}{% endif %}{% endblock %} -{% block Description %}Контактная информация маркетплейс-агрегатора «Окнардии»: адрес, телефоны и email для связи, персоны.{% endblock %} +{% block Description %}Контактная информация маркетплейса Окнардия: адрес офиса, email info@oknardia.ru, руководство и учредители, персоны компании.{% endblock %} -{% block Keywords %}Контакты, контактная информация, телефон для связи, email для связи, адрес, адрес офиса, персоны, Окнардия, маркетплейс-агрегатор «Окнардии»{% endblock %} +{% block Keywords %}контакты окнардия, контактная информация, email для связи, адрес офиса, маркетплейс окон, агрегатор окон, руководство окнардии, организационные вопросы, партнерство{% endblock %} + +{% block Author4Meta %}Контакты маркетплейса «Окнардия»{% endblock %} + +{% block CopyrightAuthor4Meta %}Маркетплейс «Окнардия»{% endblock %} {% block Top_JS1%} {% endblock %} +{% block Top_Meta1 %}{# #} + {# Удалить: устаревшие теги если появятся #} + + + + + + + + + + + + + + + + + + + + +{# #}{% endblock %} + +{% block ADD_TO_HEAD %} + {# JSON-LD: страница контактов — Organization + ContactPoint + BreadcrumbList #} + + +{% endblock %} + {% block Main_Content %}
    +{# Хлебные крошки: НАЧАЛО #} +
    +
    + +
    +
    +{# Хлебные крошки: КОНЕЦ #} +

    Контакты «Окнардия»

    @@ -39,7 +137,7 @@ img {background-color: whitesmoke;}
    - Сергей Еремин — CEO/CTO «Окнардия», организационные вопросы, технические решения, партнерство + Сергей Еремин — CEO/CTO «Окнардия», организационные вопросы, технические решения, партнерство

    Сергей Еремин

    CEO/CTO

    организационные вопросы, технические решения, партнерство
    @@ -61,7 +159,7 @@ img {background-color: whitesmoke;}
    - Тимофей Молдованин — CFO/COO «Окнардия», финансовые и коммерческие вопросы + Тимофей Молдованин — CFO/COO «Окнардия», финансовые и коммерческие вопросы

    Тимофей Молдованин

    CFO/COO

    финансовые и коммерческие вопросы
    diff --git a/oknardia/templates/index.html b/oknardia/templates/index.html index d854a62..583be90 100755 --- a/oknardia/templates/index.html +++ b/oknardia/templates/index.html @@ -1,24 +1,77 @@ {% extends "base.html" %} {% load static %} -{% block Title %}: выбор пластиковых окон в квартиру. Поставщики, цены, описания, характеристики, отзывы.{% endblock %} +{% block Title %}Окнардия: агрегатор цен на пластиковые окна и услуги их установки{% endblock %} -{% block Description %}Окнардия: Здесь собраны цены на установку пластиковых окон. Просто введите адрес и получите актуальные предложения от ведущих поставщиков окон, подробные характеристики профилей и стеклопакетов, информацию о скидках. Никаких предварительных замеров! Мы уже знаем размеры проёмов в квартире, рекомендованные схемы открывания, требования к стеклопакетам, профилю и многое другое. Замена пластиковых окон — ответственное мероприятие. Мы помогаем сделать объективный выбор.{% endblock %} +{% block Description %}Агрегатор цен на пластиковые окна в типовых домах России. Введите адрес, укажите тип квартиры и сравните цены поставщиков на установку и характеристики предложений: оконный профиль, стеклопакет, скидки, дополнительные услуги.{% endblock %} -{% block Keywords %}Цены на окна, цены на пластиковые окна, стоимость замены окон, пластиковые окна в квартиру, скидки на пластиковые окна, окна в квартиру, размеры окон, скидки на пластиковые окна, характеристики пластиковых окон, окна в панельный дом, окна в блочный дом.{% endblock %} +{% block Keywords %}цены на окна, пластиковые окна, замена окон, услуги установки окон, профили окон, стеклопакеты, скидки на окна, окна в квартиру, размеры оконных проёмов, поставщики окон{% endblock %} -{% block Top_JS1 %}{# comment #} -{# endcomment #} - +{% block Author4Meta %}ОКНАРДИЯ — Оконный Агрегатор{% endblock %} + +{% block CopyrightAuthor4Meta %}ОКНАРДИЯ — Оконный Агрегатор{% endblock %} + +{% block Top_Meta1 %}{# #} + + {# #} + + + + + + + + {# #} + + + + + +{# #}{% endblock %} + +{% block Top_JS1 %} {% endblock %} -{% block Top_CSS2 %} - +{% block Top_CSS2 %} {% endblock %} +{% block ADD_TO_HEAD %}{# #} + +{# #}{% endblock %} + {% block Main_Content %} + {# --- Open Graph (OG) --- #} + + + + + + {# --- Twitter Card --- #} + + + + {# --- Даты публикации и обновления --- #} + + +{% endblock %} -{% comment %}{% block Description %}Цены на плаcтиковые окна для серии {{ BASE_SERIA }} ({{ APART }} квартира, {{ ADDRESS }}) :: {% for CurOffer in PRICE_FRAME %}Поставщик: {{ CurOffer.MERCHANT }}; Комплектация: {{ CurOffer.SETS_NAME }}; Цена: {{ CurOffer.FIN_PRICE }}₽ :: {% endfor %}{% endblock %}{% endcomment %} - -{% block Keywords %}цены окон, серия {{ BASE_SERIA }}, {{ BASE_SERIA }}, стоимость окон, окна для {{ BASE_SERIA }}, размеры окон, проемы серии {{ BASE_SERIA }}, окна в {{ APART|safe }}, скидки на окна, {{ ADDRESS }}, оконный профиль, {% for CurOffer in PRICE_FRAME %}{{ CurOffer.MERCHANT }}, {{ CurOffer.PVC_NAME }}, {{ CurOffer.PVC_MANUFACTURER }}, {{ CurOffer.GLAZING_MARK }}, {% endfor %} характеристики пластиковых окон, {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }} см., {% endfor %}{{ META_KEYWORDS|default:"" }}{% endblock %} - -{% block Top_JS3%} + {% endblock %} +{% block ADD_TO_HEAD %}{% comment %} + JSON-LD микроразметка для поисковых систем (Schema.org): + - BreadcrumbList: хлебные крошки для навигации в поиске + - Organization: информация о бренде/компании + - Product: типовое окно с полной информацией + - Рейтинги и цены берутся из таблицы предложений (price_offers_for_one_window_frame.html) + {% endcomment %}{% endblock %} + {% block Description %}Цены на типовое окно {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:0 }}x{{ I_WIN_DIM.iWinHight|floatformat:0 }} см. для домов серий {% for I in SERIA_FOR_WIN %}{% if forloop.last %} и {% elif forloop.first %}{% else %}, {% endif %}{{ I.sName }}{% endfor %}{% endfor %}.{% endblock %} {% comment %}{% block Description %}Цены на пластиковые окна для серии {{ BASE_SERIA }} ({{ APART }} квартира, {{ ADDRESS }}) :: {% for CurOffer in PRICE_FRAME %}Поставщик: {{ CurOffer.MERCHANT }}; Комплектация: {{ CurOffer.SETS_NAME }}; Цена: {{ CurOffer.FIN_PRICE }}₽ :: {% endfor %}{% endblock %}{% endcomment %} @@ -146,12 +281,14 @@ $(function () { // инициализация и обработка попове
    -

    Цены на окно {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth_mm|floatformat:0 }}×{{ I_WIN_DIM.iWinHight_mm|floatformat:0 }}{% endfor %} мм. (типовое)

    +

    Цены на окно {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth_mm|floatformat:0 }}×{{ I_WIN_DIM.iWinHight_mm|floatformat:0 }}{% endfor %} мм. (типовое)

    -

    Типовой проём {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:1 }}×{{ I_WIN_DIM.iWinHight|floatformat:1 }}{% endfor %} cм. представлен в домах серий: {% for I in SERIA_FOR_WIN %}{% if forloop.last %} и {% elif forloop.first %}{% else %}, {% endif %}{{ I.sName }}{% endfor %}. База «Окнардии» размещено {{ NUM_TOTAL_OFFER_N_WORD }} цен для окон в такой проем (из них в архиве {{ NUM_ARCHIVE_OFFER }}). Предложено {{ NUM_FLAP_VARIATION_IN_WORD }} открывания от {{ NUM_TOTAL_FIRM_N_WORD }}.

    +

    Типовой проём {% for I_WIN_DIM in FLAP_DIM %}{{ I_WIN_DIM.iWinWidth|floatformat:1 }}×{{ I_WIN_DIM.iWinHight|floatformat:1 }}{% endfor %} cм. представлен в домах серий: {% for I in SERIA_FOR_WIN %}{% if forloop.last %} и {% elif forloop.first %}{% else %}, {% endif %}{{ I.sName }}{% endfor %}. База «Окнардии» размещено {{ NUM_TOTAL_OFFER_N_WORD }} цен для окон в такой проем (из них в архиве {{ NUM_ARCHIVE_OFFER }}). Предложено {{ NUM_FLAP_VARIATION_IN_WORD }} открывания от {{ NUM_TOTAL_FIRM_N_WORD }}.

    - {# Микроразмектка: названеи продукта #} + {# Микроразметка: название продукта и марка #} + +
    @@ -176,8 +313,6 @@ $(function () { // инициализация и обработка попове

    В таблице представлены только цены поставщиков из базы «Окнардия». Клик на названии набора отобразит детальную спецификацию каждого предложения: профиль рамы и створки, схему стеклопакета, фурнитуру, элементы отлива, подоконника, откоса, системы климат-контроля) и сопутствующие услуги. Предложения выводятся блоками. Очередной блок выводится кнопкой «Ещё коммерческие предложения окон» под таблицей. Детальные технические характеристики стеклопакетов, профилей и описание сопутствующих услуг можно посмотреть и сравнить с помощью кнопки «Сравнить выбранные».

    - {# Микроразмектка: названеи продукта #} -
    diff --git a/oknardia/templates/price/price_offers_for_one_window_frame.html b/oknardia/templates/price/price_offers_for_one_window_frame.html index 4d236d5..c507b27 100755 --- a/oknardia/templates/price/price_offers_for_one_window_frame.html +++ b/oknardia/templates/price/price_offers_for_one_window_frame.html @@ -6,8 +6,8 @@ {% if forloop.first %} {# красивые чекбоксы BEGIN #}
    {# красивые чекбоксы END #} - -

    {{ CurOffer.MERCHANT }} – {{ CurOffer.SETS_NAME }}

    + +

    {{ CurOffer.MERCHANT }} – {{ CurOffer.SETS_NAME }}

    ■ Профиль: {{ CurOffer.PVC_NAME|safe }} ({{ CurOffer.PVC_MANUFACTURER }}) ■ {{ CurOffer.GLAZING_NAME_B|safe }} ({{ CurOffer.GLAZING_MARK }}) @@ -29,17 +29,15 @@
    {{ CurOffer.SETS_DATA_MODIFY|date:"d.M.Y" }} - - + + для оконого набора «{{ CurOffer.SETS_NAME }}» компании «{{ CurOffer.MERCHANT }}» состоит из:{% else %}Рейтинг не присвоен{% endif %}" - data-toggle="popover">рейтинг: {% for Star in CurOffer.SETS_RATING_STARTS %}{% if Star == 0 %}{% else %}{% endif %}{% endfor %} {% if CurOffer.SETS_RATING > -0.1 %} {{ CurOffer.SETS_RATING|stringformat:".2f" }}{% endif %} + data-toggle="popover">рейтинг: {% for Star in CurOffer.SETS_RATING_STARTS %}{% if Star == 0 %}{% else %}{% endif %}{% endfor %} {% if CurOffer.SETS_RATING > -0.1 %}{{ CurOffer.SETS_RATING|stringformat:".2f" }}{% endif %}
    - - - {% endif %} @@ -50,10 +48,8 @@ {{ CurOffer.TOTAL|stringformat:".2f"|price_format }} {% if CurOffer.DISCOUNT < 0.1 %}—{% else %}−{{ CurOffer.DISCOUNT|stringformat:".1f" }}%{% endif %} - + Итого: {{ CurOffer.FIN_PRICE|stringformat:".2f"|price_format }}  - - {% if CurOffer.DIM|length == 1 %} diff --git a/oknardia/templates/rating/profiles_rating.html b/oknardia/templates/rating/profiles_rating.html index ac8e6f3..ed344f3 100755 --- a/oknardia/templates/rating/profiles_rating.html +++ b/oknardia/templates/rating/profiles_rating.html @@ -1,21 +1,101 @@ {% extends "base.html" %}{% load static %} -{% block Title %}: Тарифы и услуги{% endblock %} +{% block Title %}Рейтинг оконных профилей | Ранжирование PVC профилей по характеристикам | Окнардия{% endblock %} {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{# block Date4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock #} +{% block Description %}Рейтинг оконных PVC профилей в базе Окнардия: ранжирование моделей профилей по теплопередаче, звукоизоляции и другим характеристикам. Сравнение пластиковых профилей.{% endblock %} -{# block Last4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock #} +{% block Keywords %}рейтинг окон, рейтинг оконных профилей, рейтинг pvc профилей, производители окон, ранжирование профилей, сравнение пластиковых окон, характеристики окон, теплопередача профилей, звукоизоляция окон{% endblock %} -{% block Description %}Тарифы и услуги маркетплейс-агрегатора Окнардия. Размещение предложений пластиковых и деревянных окон, обновление цен на окна, рекламные баннеры и виджеты на сайт оконной компании.{% endblock %} +{% block Author4Meta %}Рейтинг оконных профилей Окнардия{% endblock %} -{% block Keywords %}типовые проекты зданий, панельное строительство, {% for CountSeria in SERIA_NAV_DIM %}серия {{ CountSeria.SERIA_R }}, {{ CountSeria.SERIA_R }}, {% endfor %}, года постройки, регионы постройки, распространённость{% endblock %} +{% block CopyrightAuthor4Meta %}Окнардия — агрегатор цен на окна{% endblock %} {% block Top_JS5 %} {% endblock %} +{% block Top_Meta1 %}{# #} + + + + + + + + + + + + + + + + + + + + +{# #}{% endblock %} + +{% block ADD_TO_HEAD %} + {# JSON-LD: BreadcrumbList для рейтинга профилей #} + + {# JSON-LD: CollectionPage для рейтинга #} + +{% endblock %} + {% block Main_Content %}
    +{# Хлебные крошки: НАЧАЛО #} +
    +
    + +
    +
    +{# Хлебные крошки: КОНЕЦ #} +

    Рейтинг оконных профилей базы «Окнардия»

    diff --git a/oknardia/templates/report/report_compare_set.html b/oknardia/templates/report/report_compare_set.html index 9c52d4f..18453af 100755 --- a/oknardia/templates/report/report_compare_set.html +++ b/oknardia/templates/report/report_compare_set.html @@ -2,19 +2,176 @@ {% load static %} {% load filters %} -{% block Title %} Сравнение характеристик оконных профилей: {% for PROFILE in LIST_PROFILE %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ PROFILE }}{% endfor %}. Сравнение характеристик стеклопакетов: {% for GLAZING in LIST_GLAZING %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ GLAZING }}{% endfor %}. Сравнение предложений окон: {% for MERCANT in LIST_MERCHANT %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ MERCANT }}{% endfor %}.{% endblock %} +{# Заголовок: человекочитаемый, ключевые слова в начале #} +{% block Title %}Сравнение окон: {% for Count in SET_LIST %}{% if not forloop.first %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}«{{ Count.SET_NAME }}» ({{ Count.MERCHANT }}){% endfor %} — характеристики профилей и стеклопакетов{% endblock %} {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Date4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %} +{% block Date4Meta %}{{ META_DATA_PUBLISH|date:"Y-m-d" }}{% endblock %} +{% block Last4Meta %}{{ META_DATA_PUBLISH|date:"Y-m-d" }}{% endblock %} -{% block Last4Meta %}{{ META_DATA_PUBLISH|date:"c" }}{% endblock %} - - -{% block Description %}Сравнение характеристик окон от поставщиков: {% for MERCANT in LIST_MERCHANT %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ MERCANT }}{% endfor %}. Сравнение профилей пластиковых окон: {% for PROFILE in LIST_PROFILE %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ PROFILE }}{% endfor %}. Сравнение характеристик стеклопакетов: {% for GLAZING in LIST_GLAZING %}{% if forloop.first %}{% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ GLAZING }}{% endfor %}.{% endblock %} +{# Description: первое слово — целевой запрос, потом конкретика #} +{% block Description %}Детальное сравнение оконных наборов: {% for Count in SET_LIST %}{% if not forloop.first %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}«{{ Count.SET_NAME }}» от {{ Count.MERCHANT }}{% endfor %}. Профили: {% for PROFILE in LIST_PROFILE %}{{ PROFILE }}{% if not forloop.last %}, {% endif %}{% endfor %}. Стеклопакеты: {% for GLAZING in LIST_GLAZING %}{{ GLAZING }}{% if not forloop.last %}, {% endif %}{% endfor %}. Теплопередача, звукоизоляция, условия монтажа.{% endblock %} {% block Keywords %}сравнение профилей пластиковых окон, {% for PROFILE in LIST_PROFILE %}{{ PROFILE }}, {% endfor %}сравнение стеклопакетов, {% for GLAZING in LIST_GLAZING %}{{ GLAZING }}, {% endfor %}сравнение поставщиков пластиковых окон, {% for MERCANT in LIST_MERCHANT %}{{ MERCANT }}, {% endfor %}характеристики пластиковых окон.{% endblock %} +{% block Top_Meta1 %} + {# Canonical — предотвращает дубли при разном порядке ID (1,2 и 2,1 — одна страница) #} + + + + + + + + + + + + + + + +{% endblock %} + +{% block ADD_TO_HEAD %}{% comment %} +JSON-LD разметка для страницы сравнения оконных наборов. +BreadcrumbList: хлебные крошки в сниппете Google. +TechArticle + mainEntity ItemList: описывает страницу как технический сравнительный материал. +Каждый набор — Product с: + - additionalProperty: полный список условий поставки и монтажа + - hasPart[0]: профиль ПВХ как вложенный Product со всеми техническими PropertyValue + - hasPart[1]: стеклопакет как вложенный Product со всеми техническими PropertyValue +Хак с запятыми: последним в каждом additionalProperty ставим фиксированный элемент + {"@type":"PropertyValue","name":"Источник данных","value":"oknardia.ru"} — благодаря этому + все условные элементы выше могут безопасно завершаться запятой. +{% endcomment %} + +{% endblock %} + {% block Top_JS3%}{% endblock %} - {% block Top_CSS1 %}{% endblock %} {% block Main_Content %}
    -

    Сравнении оконных наборов:{% for Count in SET_LIST %}{% if forloop.first %} {% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ Count.SET_NAME }}{% if forloop.last %}.{% endif %}{% endfor %}

    + {# Хлебные крошки: Главная → Каталог → Оконные наборы (ссылка) → текущее сравнение #} + + {# Исправлена опечатка: «Сравнении» → «Сравнение» #} +

    Сравнение оконных наборов:{% for Count in SET_LIST %}{% if forloop.first %} {% else %}{% if forloop.last %} и {% else %}, {% endif %}{% endif %}{{ Count.SET_NAME }}{% if forloop.last %}.{% endif %}{% endfor %}

    Оконный набор — это комплект оконного профиля (рамы и сворки), стеклопакета, фурнитуры и уплотнителей — готовое окно в сборе для установки в проём. В набор может входить отлив, подоконник, откос, встраиваемые системы климат-контроля, оконная фурнитура открывания, запоры, уплотнители, москитная сетка… а также сопутствующие услуги: демонтаж старых и установка новых окон, доставка, гарантийное обслуживание, уборка, вынос и утилизация строительного мусора, защитное укрытие мебели на время монтажа и другое.

    -

    В таблицу сравнения услуг и условий, входящих в оконные наборы, добавлены следующие производители и поставщики:

    + {# h4 → h2 для правильной иерархии заголовков (SEO); визуальный размер сохраняем через style #} +

    В таблицу сравнения услуг и условий, входящих в оконные наборы, добавлены следующие производители и поставщики:

      {% for MERCANT in LIST_MERCHANT %}
    • {{ MERCANT }}.
    • {% endfor %}
    -

    В средней части таблице вы сможете сравнить характеристики оконных профилей в наборах:

    +

    В средней части таблицы вы сможете сравнить характеристики оконных профилей в наборах:

      {% for PROFILE in LIST_PROFILE %}
    • {{ PROFILE }}.
    • {% endfor %}
    -

    Нижний блок таблицы посвящен характеристикам и сравнению стеклопакетов в наборах. Формулы выбранных стеклопакетов:

    +

    Нижний блок таблицы посвящен характеристикам и сравнению стеклопакетов в наборах. Формулы выбранных стеклопакетов:

      {% for GLAZING in LIST_GLAZING %}
    • {{ GLAZING }}.
    • {% endfor %}
    @@ -66,14 +231,18 @@ Поставщик:
    компания, предлагающая установку окон{% for Count in SET_LIST %} -

    {{ Count.MERCHANT }}


    + + {# h2 в ячейке таблицы — семантический мусор; заменяем на strong #} + {{ Count.MERCHANT }}
    {{ Count.MERCHANT }}
    {% if Count.IS_COMMERCIAL %}{{ Count.MERCHANT_URL_SHOT|truncatechars:30 }}{% else %}{{ Count.MERCHANT_URL_SHOT|truncatechars:30 }}{% endif %}
    в каталоге
    {% endfor %} - + + Название набора:{% for Count in SET_LIST %} {{ Count.SET_NAME|truncatechars:25 }}{% endfor %} - + + Рейтиг «Окнардии»:{% for Count in SET_LIST %} {% for Star in Count.RATING_SET %}{% if Star == 0 %}{% else %}{% endif %}{% endfor %} {% if Count.RATING_SET_N > 0.1 %}{{ Count.RATING_SET_N|stringformat:".2f" }}{% endif %} {% if Count.PROFILE_FILLET != "" %}{{ Count.PROFILE_FILLET }}{% else %}—{% endif %}{% endfor %} Уплотнитель:{% for Count in SET_LIST %} - {% if Count.PROFILE_SEAL_DESCRIPTION != "" %}{{ Count.PROFILE_SEAL_DESCRIPTION|capfirst }}{% else %}—{% endif %}{% endfor %} + {% if Count.PROFILE_SEAL_DESCRIPTION != "" %}{{ Count.PROFILE_SEAL_DESCRIPTION|capfirst }}{% else %}—{% endif %}{% endfor %} Прочие характеристики:{% for Count in SET_LIST %} {% if Count.PROFILE_OTHER != "" %}{{ Count.PROFILE_OTHER }}{% else %}—{% endif %}{% endfor %} diff --git a/oknardia/templates/report/report_last_user_visit.html b/oknardia/templates/report/report_last_user_visit.html index 5e04885..1a490e7 100755 --- a/oknardia/templates/report/report_last_user_visit.html +++ b/oknardia/templates/report/report_last_user_visit.html @@ -1,8 +1,8 @@ -{% load filters %} -{% if LAST_VISIT and LAST_VISIT|length >= 1 %}
    -
    Цены на окна просмотренные вами:
    -
    +{% load static %} +
    + -
    {% endif %} \ No newline at end of file +
    + diff --git a/oknardia/templates/report/show_big_flap_pictures.html b/oknardia/templates/report/show_big_flap_pictures.html index 417448a..8aff898 100755 --- a/oknardia/templates/report/show_big_flap_pictures.html +++ b/oknardia/templates/report/show_big_flap_pictures.html @@ -1,13 +1,13 @@ -{# Отрисовка больших картинок с проемами и схамаи открывания #}{% load static %}{% if WIN_DIM %} +{# Отрисовка больших картинок с проемами и схемами открывания #}{% load static %}{% if WIN_DIM %} {% for I_WIN_DIM in FLAP_DIM %} -
    -
    {{ I_WIN_DIM.sDescription }}. Размер {{ I_WIN_DIM.iWinWidth|stringformat:
    -
    - {{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0×{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 мм.
    {% if not I_WIN_DIM.iQuantity == 0 %} - {{ I_WIN_DIM.iQuantity }} шт.{% for I_II in I_WIN_DIM.qStr %}{% endfor %}
    {% endif %} - {{ I_WIN_DIM.sDescription }}{% if not I_WIN_DIM.iQuantity == 0 %}
    - цены только этого типового окна{% endif %} -
    +
    +
    {{ I_WIN_DIM.sDescription }}. Размер {{ I_WIN_DIM.iWinWidth|stringformat:
    +
    + {{ I_WIN_DIM.iWinWidth|stringformat:".0f" }}0×{{ I_WIN_DIM.iWinHight|stringformat:".0f" }}0 мм.
    {% if not I_WIN_DIM.iQuantity == 0 %} + {{ I_WIN_DIM.iQuantity }} шт.{% for I_II in I_WIN_DIM.qStr %}{% endfor %}
    {% endif %} + {{ I_WIN_DIM.sDescription }}{% if not I_WIN_DIM.iQuantity == 0 %}
    + цены только этого типового окна{% endif %} +
    {% endfor %}{% comment %} + {# JSON-LD: TechArticle — технический справочный материал о серии типового строительства #} +{% endblock %} {% block Top_JS1 %} {% endblock %} +{% block Top_Meta1 %}{# #} + {# Удалить: itemprop microdata, rel=standout, twitter:domain — устаревшие теги #} + + + + + + + + + + + + + + + + + + + + + + + +{# #}{% endblock %} + +{% block ADD_TO_HEAD %} + {# JSON-LD: страница статистики типовых серий — CollectionPage + BreadcrumbList + DataCatalog #} + + +{% endblock %} + {% block Main_Content %}
    +{# Хлебные крошки: НАЧАЛО #} +
    +
    + +
    +
    +{# Хлебные крошки: КОНЕЦ #} +

    Типовые серии домов в базе «Окнардия»

    @@ -38,15 +126,6 @@ DimColor = []; for (i1=0; i1<=step; i1++ ) for (i2=step; i2>=0; i2-- ) for (i3=0; i3<=step; i3++ ) { - //document.write("  -- "); - //document.write( "#" - // + ("00"+(i1*step_tone).toString(16)).substr(-2) - // + ("00"+(i2*step_tone).toString(16)).substr(-2) - // + ("00"+(i3*step_tone).toString(16)).substr(-2) + "
    "); DimColor.push("#" + ("00"+(i1*step_tone).toString(16)).substr(-2) + ("00"+(i2*step_tone).toString(16)).substr(-2) diff --git a/oknardia/templates/seria_info/geo_map.html b/oknardia/templates/seria_info/geo_map.html index a3d011d..48185bf 100755 --- a/oknardia/templates/seria_info/geo_map.html +++ b/oknardia/templates/seria_info/geo_map.html @@ -2,8 +2,7 @@ {% block Top_JS5 %} {% if MAP_JS %}{% else %}{# #} - {# #}{% block Top_JS1 %}{% endblock %}{% block Top_JS2 %}{% endblock %}{% block Top_JS3 %}{% endblock %}{% block Top_JS4 %}{% endblock %}{% block Top_JS5 %}{% endblock %}{% block Top_Meta1 %}{% endblock %} - - - - -
    -
    -

     
     

    - -

    Служебный интерфейс закрыт

    - -

    Доступ только для админов! Поисковикам и - пользователям лезть сюда не за чем…

    -
    -
    - -
    -
    - - - {##}Рейтинг@Mail.ru{##} - {# #}Яндекс.Метрика{# #} - {# #}{# #} - - {# #} -
    -
    - © oknardia.ru, 2015-{% now "Y" %}. -
    -
    - - - \ No newline at end of file diff --git a/oknardia/templates/service/tmp.html b/oknardia/templates/service/tmp.html index dc41435..a98584d 100755 --- a/oknardia/templates/service/tmp.html +++ b/oknardia/templates/service/tmp.html @@ -57,7 +57,7 @@ $(window).load(function(){var images = $('.half');images.each(function(i){$(this
  • Размещено 22 оконных набора в предложениях. Размещаются как пластиковые, так и деревянные окна.
  • С «Окнардией» работают уже семь оконных-компании партнёра.
  • — Добавлен функционал сравнения характеристик оконных предложений и отдельных компонентов этих предложений.
  • -
  • Создан каталог профилей, стандартных проёмов, типовых серий домов, оконных компаний. В будущем будет каталог стеклопакетов и фурнитуры… планов много.
  • +
  • Создан каталог профилей, стандартных проёмов, типовых серий домов, оконных компаний. В будущем будет каталог стеклопакетов и фурнитуры… планов много.
  • Построен алгоритм расчёта реальных рейтингов предложений, профилей, стеклопакетов и сервиса компаний. Рейтинги не на базе «общественного голосования», «опросов» или измерением «интернет-популярности», а на базе физических характеристик и измеримых параметров. Таким образом — это объектовые рейтинги.
  • Разработан виджет, который позволяет оконной компании реализовать функционал «Окнардии» на собственном сайте.
  • Расширены медиа-возможности проекта: баннеры, посты в блоге, специальное выделение.
  • diff --git a/oknardia/templates/tariff.html b/oknardia/templates/tariff.html index 950156e..b8c6bd4 100755 --- a/oknardia/templates/tariff.html +++ b/oknardia/templates/tariff.html @@ -1,16 +1,20 @@ {% extends "base.html" %}{% load static %} -{% block Title %}Тарифы и услуги{% endblock %} +{% block Title %}Тарифы и услуги маркетплейса Окнардия | Цены на размещение предложений окон{% endblock %} {% block Add_Body_Attribute %} style="padding-top:70px;"{% endblock %} -{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} +{% block Date4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"Y-m-d" }}{% else %}{% now "c" %}{% endif %}{% endblock %} -{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"c" }}{% else %}{% now "c" %}{% endif %}{% endblock %} +{% block Last4Meta %}{% if PUB_DAT %}{{ PUB_DAT|date:"Y-m-d" }}{% else %}{% now "c" %}{% endif %}{% endblock %} -{% block Description %}Тарифы и услуги маркетплейс-агрегатора Окнардия. Размещение предложений пластиковых и деревянных окон, обновление цен на окна, рекламные баннеры и виджеты на сайт оконной компании.{% endblock %} +{% block Description %}Тарифы размещения предложений по установке пластиковых и деревянных окон на маркетплейсе Окнардия. Пять тарифных планов: альфа (бесплатно), бета, дельта, мю (медийный), омега (виджет). Обновление цен, баннеры, публикации в блог, электронные заявки.{% endblock %} -{% block Keywords %}типовые проекты зданий, панельное строительство, {% for CountSeria in SERIA_NAV_DIM %}серия {{ CountSeria.SERIA_R }}, {{ CountSeria.SERIA_R }}, {% endfor %}, года простойки, регионы построки, распространенность{% endblock %} +{% block Keywords %}тарифы окнардия, размещение предложений окон, цены на окна, маркетплейс окон, услуги для оконных компаний, виджет окон, баннеры на сайт, каталог окон, установка окон, продажа пластиковых окон, медийное продвижение окон{% endblock %} + +{% block Author4Meta %}: Тарифы и услуги маркетплейса «Окнардия»{% endblock %} + +{% block CopyrightAuthor4Meta %}: Тарифы маркетплейса «Окнардия»{% endblock %} {% block Top_JS1%} {% endblock %} +{% block Top_Meta1 %}{# #} + {# Удалить: itemprop microdata, rel=standout, twitter:domain — устаревшие теги #} + + + + + + + + + + + + + + + + + + + + + + + +{# #}{% endblock %} + +{% block ADD_TO_HEAD %} + {# JSON-LD: страница тарифов — CollectionPage + BreadcrumbList + PriceSpecification #} + + + +{% endblock %} + {% block Main_Content %}
    +{# Хлебные крошки: НАЧАЛО #} +
    +
    + +
    +
    +{# Хлебные крошки: КОНЕЦ #} +

    Направления сотрудничества с «Окнардия» и тарифы

    - {% if SENDER %}{% if SENDER == "Ok!" %}

    Спасибо за ваше обращение. Мы обязательно свяжемся с вами.

    {% elif SENDER == "Error!" %}

    Что-то пошло не так. Не удалось отправить e-mail. Попробуйте еще раз или используте для связи info@oknardia.ru

    {% endif %}{% endif %} + {% if SENDER %}{% if SENDER == "Ok!" %}

    Спасибо за ваше обращение. Мы обязательно свяжемся с вами.

    {% elif SENDER == "Error!" %}

    Что-то пошло не так. Не удалось отправить e-mail. Попробуйте еще раз или используете для связи info@oknardia.ru

    {% endif %}{% endif %} @@ -216,12 +494,318 @@ $(window).load(function(){let images = $('.half');images.each(function(i){$(this
    -

     

    -

    Мы открыты к сотрудничеству. Много идей в наших планах (в том числе универсальный калькулятор окон, виджет калькулятора, генератор смет и прейскурантов и еще много чего) и если у вас есть потребность в дополнительных разработках для рынка окон, будем рады обсудить возможные формы сотрудничества.

    -
    +

     

    +

    Мы открыты к сотрудничеству. Много идей в наших планах (в том числе универсальный калькулятор окон, виджет калькулятора, генератор смет и прейскурантов и еще много чего) и если у вас есть потребность в дополнительных разработках для рынка окон, будем рады обсудить возможные формы сотрудничества.

    +
    - +{# FAQ секция для SEO: НАЧАЛО #} +
    +
    +

    Часто задаваемые вопросы о тарифах и услугах

    + +
    + + {# Вопрос 1: Что такое Окнардия #} +
    + +
    +
    + Окнардия — это агрегатор (маркетплейс) для сравнения цен на установку пластиковых и деревянных + окон в зданиях типового строи­тельства России. Пользователи указывают адрес дома, система + распознаёт серию здания и выдаёт типовые размеры оконных проёмов, а затем показывает предложения + от поставщиков на установку и замену окон. +
    +
    +
    + + {# Вопрос 2: Выбор тарифа #} +
    + +
    +
    + Выбор тарифа зависит от ваших целей: +
      +
    • Альфа (бесплатно) — для тестирования и ознакомления с платформой; +
    • +
    • Бета (300₽/мес) — для базового размещения с логотипом и двумя + предло­жениями; +
    • +
    • Дельта (1500₽/мес) — для расширенного каталога с 12 наборами, + публикациями и всплытиями; +
    • +
    • Мю (500₽/мес) — для медийного продвижения с баннерами и публикациями + в блог; +
    • +
    • Омега (9000₽/мес) — полный пакет с виджетом на ваш сайт и максимум + возможностей. +
    • +
    +
    +
    +
    + + {# Вопрос 3: SEO эффект #} +
    + +
    +
    + Логотип вашей компании в ценовой выдаче содержит ссылку на ваш сайт — это мощный + источник качественных внешних ссылок (backlinks), что положительно влияет на ранжирование вашего сайта + в поисковых системах. Публикации в блог «Окнардии» также способствуют SEO за счёт + релевантного контента и внутренних ссылок. SEO-эффект сохраняется пока ваша подписка активна, плюс ещё + примерно шесть месяцев после завершения (кеширование и остаточная ценность ссылок). +
    +
    +
    + + {# Вопрос 4: Всплытия #} +
    + +
    +
    + «Всплытие» гарантирует присутствие ваших предложений в приоритетном блоке выдачи и в Rich + Snippet'ах (виджеты, острова) поисковиков. Позиция может варьи­роваться из-за сортировки по удалённости + офиса от адреса клиента, но видимость в блоке гаранти­рована. Важный бонус: поисковики + интенсивнее переинде­ксируют предложения с частыми обновлениями, что повышает вероятность появления + в поисковых сниппетах и медийных виджетах (Google и Яндекс). На плане Дельта доступно + восемь всплытий в месяц, на Омега — тоже восемь. +
    +
    +
    + + {# Вопрос 5: Обновления цен #} +
    + +
    +
    + Да, каждый тариф предусма­тривает определённое количество обновлений в месяц. Обновления + применяются ко всем проёмам и ценам выбранного набора: +
      +
    • Альфа — ⅓ обновления (в среднем один раз в три месяца);
    • +
    • Бета — одно обновление в месяц;
    • +
    • Дельта — шесть обновлений в месяц;
    • +
    • Мю — нет обновлений (фокус на медийном продвижении и баннерах); +
    • +
    • Омега — восемь обновлений в месяц.
    • +
    +
    +
    +
    + + {# Вопрос 7: Стартовая установка #} +
    + +
    +
    + Стартовая установка — это единовре­менный платёж за подготовку и размещение вашей первой + ценовой информации, настройку профиля компании, загрузку логотипа, описания компании и ваших + наборов. Стоимость варьируется от 0₽ (Альфа) до 45 000₽ (Омега) в зависимости от сложности + и объёма работ. После включения тариф переходит на ежемесячное взимание по устано­вленной + цене. +
    +
    +
    + + {# Вопрос 8: Скидки за год #} +
    + +
    +
    + Да, при оплате годовым авансом преду­смотрены щедрые скидки: +
      +
    • Бета — 30% скидка (2 520₽ вместо 3 600₽);
    • +
    • Дельта — 40% скидка (13 800₽ вместо 23 000₽);
    • +
    • Мю — 20% скидка (5 200₽ вместо 6 500₽);
    • +
    • Омега — 35% скидка (70 200₽ вместо 108 000₽).
    • +
    + Авансовый платёж включает стартовую установку и полный год взимания ежемесячного тарифа. +
    +
    +
    + + {# Вопрос 9: Длительность эффекта #} +
    + +
    +
    + Логотип с ссылкой на ваш сайт работает пока ваша подписка активна. После завершения подписки + SEO-эффект продолжает сохраняться примерно 6 месяцев благодаря кешированию поисковыми системами и остаточной + ценности внешних ссылок. Это означает, что даже если вы временно прекратили размещение, ваш сайт + получает положи­тельный эффект от ссылок ещё полгода. +
    +
    +
    + + {# Вопрос 10: Публикации в блоге #} +
    + +
    +
    + Логотип с ссылкой на ваш сайт работает пока ваша подписка активна. После завершения подписки + SEO-эффект продолжает сохраняться примерно шесть месяцев благодаря кешированию поисковыми системами + и остаточной ценности внешних ссылок. Это означает, что даже если вы временно прекратили + размещение, ваш сайт получает положи­тельный эффект от ссылок ещё полгода. +
    +
    +
    + + {# Вопрос 11: Баннеры и SEO #} +
    + +
    +
    + Баннеры имеют мощный престижный эффект: ваша компания отображается между блоками ценовых предложений и на страницах + каталога, украшая платформу и позиционируя вас как ведущего поставщика. Благодаря баннерам можно + практически «забренди­ровать» весь сайт так, что он будет воспри­ниматься почти как собственный + проект вашей компании. Баннеры размером 100% × 175px могут быть графическими, видео или HTML с CSS/JS + анимацией. Доступны на плане Мю (медийный). Кроме того, баннеры на Окнардии содержат прямые + HTML-ссылки (без редиректов и JavaScript), что позволяет поисковикам их полностью индекси­ровать. + Каждый баннер — это полноценный backlink на ваш сайт, дающий SEO-эффект. +
    +
    +
    + + {# Вопрос 12: Виджет #} +
    + +
    +
    + «Виджет. ОКНАРДИЯ» — это встраиваемый фрейм-блок (iframe), который устана­вливается на сайт + поставщика окон. Виджет позволяет посетителям указать адрес дома и выбрать квартиру, после чего видят + типовые размеры проёмов, схемы открывания и ваши предложения (наборы окон) с ценами — всё + прямо на вашем сайте. Это повышает конверсию и удержание клиента. Пример и инструкции по установке + доступны на widget.oknardia.ru (примечание: + сайт может быть временно недоступен). +
    +
    +
    + + {# Вопрос 13: Специальные пожелания и гибкость #} +
    + +
    +
    + «Окнардия» — гибкий и открытый к сотрудни­честву проект. Если вас интересуют специальные условия, + кастомные решения, расширенные возможности или неста­ндартные формы партнёрства, свяжитесь + с командой проекта. Мы обсуждаем любые предложения: униве­рсальные калькуляторы окон, + специали­зированные виджеты, интеграция ваших систем, генераторы смет и прейску­рантов, анали­тические + отчёты и многое другое. Ваши идеи и пожелания — важная часть развития платформы. +
    +
    +
    + + {# Вопрос 14: Типовые размеры #} +
    + +
    +
    + Размеры окон в каталоге зависят от серии типового строи­тельства. Система распознаёт серию по адресу + и выдаёт все типовые раскладки проёмов и схемы открывания для данной серии (например, П-44, + 5-этажка, кирпичный и т. п.). На каждый набор наборов окон вы можете разместить + предложения под разные комплектации: разные профили, стеклопакеты, фурнитуру, варианты монтажа и отделки. +
    +
    +
    + +
    + +
    +
    +{# FAQ секция для SEO: КОНЕЦ #} + +