mod: описание DSL + синтаксис для фильтрации и комбинированных блоков
This commit is contained in:
+97
-41
@@ -19,10 +19,31 @@
|
|||||||
|
|
||||||
## 2. Синтаксис и структура JSON DSL
|
## 2. Синтаксис и структура JSON DSL
|
||||||
|
|
||||||
Массив `hub` представляет собой список позиционных кортежей (массивов). Порядок элементов в кортеже фиксирован, при этом все элементы, кроме первого (`slug`), являются опциональными.
|
Массив `hub` представляет собой список позиционных кортежей (массивов). Порядок элементов в кортеже строго фиксирован. Все элементы, кроме первого (`slug` / `source`), являются опциональными и имеют безопасные значения по умолчанию.
|
||||||
|
|
||||||
Позиционный порядок параметров: `[ "slug", "view_mode", limit, "sort", extra ]`
|
Позиционный порядок параметров: `[ "slug", "view_mode", limit, "sort", extra ]`
|
||||||
|
|
||||||
|
### Описание позиций кортежа:
|
||||||
|
|
||||||
|
1. **`slug` / `source` (str, 1-я позиция, обязательный)**:
|
||||||
|
- Слаг точечной статьи/категории (например, `"cassettes-studio"`).
|
||||||
|
- Динамическая выборка с двоеточием (например, `"offers:artist:the-beatles"`, `"articles:type:info"`).
|
||||||
|
- Модуль/плагин с префиксом `!` (например, `"!promo-mandarin"`).
|
||||||
|
|
||||||
|
2. **`view_mode` (str, 2-я позиция, опциональный, default зависит от `ArticleType` или `"grid"`)**:
|
||||||
|
- Название компонента рендеринга (шаблона): `carousel`, `grid`, `list`, `teaser`, `full`, `slider`.
|
||||||
|
- Поддерживает составной синтаксис через `+` (например, `"teaser+list"`).
|
||||||
|
|
||||||
|
3. **`limit` (int | str, 3-я позиция, опциональный, default=`10`)**:
|
||||||
|
- Количество выбираемых элементов (например, `10`, `50`).
|
||||||
|
- Для составных шаблонов задаётся через `+` (например, `"2+15"`).
|
||||||
|
|
||||||
|
4. **`sort` (str, 4-я позиция, опциональный, default=`"new+"`)**:
|
||||||
|
- Правило сортировки элементов выборки (см. правила ниже: `new+`, `price+`, `price-`, `random` и т.д.).
|
||||||
|
|
||||||
|
5. **`extra` (dict, 5-я позиция, опциональный, default=`{}`)**:
|
||||||
|
- Произвольный словарь с дополнительными настройками блока (например, `{"title": "Кастомный заголовок"}`).
|
||||||
|
|
||||||
### Правила синтаксиса:
|
### Правила синтаксиса:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -32,6 +53,7 @@
|
|||||||
["source-slug", "view_mode", limit],
|
["source-slug", "view_mode", limit],
|
||||||
["source-slug", "view_mode", limit, "sort_rule"],
|
["source-slug", "view_mode", limit, "sort_rule"],
|
||||||
["source-slug", "view_mode", limit, "sort_rule", {"title": "Кастомный заголовок"}],
|
["source-slug", "view_mode", limit, "sort_rule", {"title": "Кастомный заголовок"}],
|
||||||
|
["articles:type:info", "teaser+list", "2+15", "new+"],
|
||||||
["!module-slug"]
|
["!module-slug"]
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -39,56 +61,88 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Спецификация блоков
|
## 3. Спецификация блоков и Мета-язык
|
||||||
|
|
||||||
### Тип A: Блок подборки товаров или контентной статьи (обычный slug)
|
### Специальные символы синтаксиса DSL
|
||||||
|
|
||||||
Выводит подборку товаров (TbOffer), полученную на основе категории, тега формата или слаг-коллекции, либо встроенную статью/баннер.
|
| Символ | Назначение | Пример | Описание |
|
||||||
|
|:--------|:-------------------------------------|:--------------------------------------------------|:-----------------------------------------------------------|
|
||||||
|
| **`!`** | Модуль / Плагин | `"!promo-mandarin"`, `"!cart-bonus"` | Запуск зарегистрированного Python-модуля |
|
||||||
|
| **`:`** | Динамическая выборка (Namespace) | `"articles:type:info"`, `"offers:artist:beatles"` | Выборка из БД (офферы или статьи) по критерию |
|
||||||
|
| **`+`** | Составной режим отображения и лимита | `"teaser+list"`, `"2+15"` | Один SQL-запрос с разбиением результатов на разные шаблоны |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Правила сортировки (`sort`)
|
||||||
|
|
||||||
|
Для параметра `sort` (4-я позиция) используются короткие наглядные обозначения направления сортировки (`+` — по убыванию/свежие/популярные, `-` — по возрастанию/старые/дешевые):
|
||||||
|
|
||||||
|
| Значение `sort` | Смысл сортировки | Эквивалент поля в БД |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| **`new+`** *(default)* | Сначала новые (новинки) | `-t_created` / `-t_article_created` |
|
||||||
|
| **`new-`** | Сначала старые | `t_created` / `t_article_created` |
|
||||||
|
| **`price+`** | Сначала дешевые | `f_offer_price` (по возрастанию) |
|
||||||
|
| **`price-`** | Сначала дорогие | `-f_offer_price` (по убыванию) |
|
||||||
|
| **`view+`** | Самые просматриваемые (хиты) | `-i_views` / `-i_article_views` |
|
||||||
|
| **`view-`** | Наименее просматриваемые | `i_views` / `i_article_views` |
|
||||||
|
| **`favorite+`** | Часто в избранном | `-i_favorites` / `-i_article_favorites` |
|
||||||
|
| **`favorite-`** | Редко в избранном | `i_favorites` / `i_article_favorites` |
|
||||||
|
| **`random`** | Случайная выборка | `?` (`order_by('?')`) |
|
||||||
|
|
||||||
|
*Примечание:* Для обратной совместимости и отказоустойчивости парсер бэкенда также принимает устаревшие текстовые значения (`newest` $\rightarrow$ `new+`, `popular` $\rightarrow$ `view+`, `price_asc` $\rightarrow$ `price+`, `price_desc` $\rightarrow$ `price-`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Тип A: Конкретная точечная сущность (Обычный slug)
|
||||||
|
|
||||||
|
Загружает конкретную статью, категорию или жанр по их собственному первичному слагу в БД.
|
||||||
|
|
||||||
Формат: `[ "slug", "view_mode", limit, "sort", extra ]`
|
Формат: `[ "slug", "view_mode", limit, "sort", extra ]`
|
||||||
|
|
||||||
Параметры (позиционные):
|
Примеры:
|
||||||
|
- `["cassettes-studio"]` — конкретная категория/статья (дефолтные view_mode по `ArticleType`, limit=10, sort="new+")
|
||||||
|
- `["guide-how-to-clean-heads", "teaser"]` — тизер конкретной статьи
|
||||||
|
|
||||||
1. `slug` (str, обязательный): Уникальный слаг TbMusicStyle, TbArticle (Категория/Тег/Статья) или идентификатор формата (например, `cassettes-studio`, `vinyl-rock`).
|
---
|
||||||
2. `view_mode` (str, опциональный, default зависит от `ArticleType`): Компонент рендеринга (шаблон):
|
|
||||||
- `carousel` → Горизонтальная карусель / слайдер.
|
### Тип B: Динамическая выборка / Запрос к БД (Префикс с двоеточием `:`)
|
||||||
- `grid` → Стандартная сетка карточек.
|
|
||||||
- `list` → Компактный вертикальный список.
|
Позволяет формировать динамические списки офферов (`offers:...`) или статей (`articles:...`) по заданным критериям без создания отдельных вьюх.
|
||||||
- `teaser` → Тизер статьи с кнопкой «Читать далее».
|
|
||||||
- `full` → Полный HTML-контент статьи, встроенный inline.
|
Формат источника (`source`):
|
||||||
- *Примечание:* Если `view_mode` не указан, шаблон выбирается автоматически в соответствии с типом сущности (`ArticleType` модели `TbArticle`), за которой закреплен слаг. У каждого `ArticleType` есть свой дефолтный шаблон.
|
- `offers:artist:<slug>` — офферы конкретного исполнителя (например, `offers:artist:the-beatles`)
|
||||||
3. `limit` (int, опциональный, default=`10`): Количество выводимых элементов (например, 5, 20).
|
- `offers:format:<slug>` — офферы конкретного формата (например, `offers:format:vinyl`)
|
||||||
4. `sort` (str, опциональный, default=`"newest"`): Правило сортировки:
|
- `offers:style:<slug>` — офферы музыкального стиля (например, `offers:style:jazz`)
|
||||||
- `newest` → -t_offer_created (новинки)
|
- `articles:type:<type>` — статьи определенного типа `ArticleType` (например, `articles:type:info`, `articles:type:blog`)
|
||||||
- `views` → -i_offer_views (самые просматриваемые)
|
- `articles:artist:<slug>` — статьи, связанные с исполнителем (например, `articles:artist:the-beatles`)
|
||||||
- `favorites` → -i_offer_favorites (самые популярные / в избранном)
|
|
||||||
- `price_asc` → f_offer_price (сначала дешевые)
|
|
||||||
- `price_desc` → -f_offer_price (сначала дорогие)
|
|
||||||
5. `extra` (dict, опциональный, default=`{}`): Дополнительные произвольные настройки блока (например, `{"title": "Переопределенный заголовок"}`).
|
|
||||||
|
|
||||||
Примеры:
|
Примеры:
|
||||||
- `["cassettes-studio"]` — подборка кассет (дефолтные view_mode по `ArticleType`, limit=10, sort="newest")
|
- `["articles:type:info", "list", 50]` — до 50 статей типа `INFO` в виде списка
|
||||||
- `["cassettes-studio", "carousel"]` — карусель студийных кассет (дефолтные limit=10, sort="newest")
|
- `["offers:artist:the-beatles", "carousel", 10, "view+"]` — 10 популярных релизов The Beatles в карусели
|
||||||
- `["cassettes-studio", "carousel", 6]` — карусель из 6 студийных кассет
|
|
||||||
- `["cassettes-studio", "carousel", 6, "views"]` — 6 самых просматриваемых кассет в карусели
|
|
||||||
- `["cassettes-studio", "carousel", 6, "views", {"title": "Хиты продаж"}]` — с переопределенным заголовком
|
|
||||||
|
|
||||||
Замечания: `view_mode` — это название зарегистрированного шаблона в системе. Если `view_mode` не указан или пуст, вид отображения выбирается автоматически в соответствии с `ArticleType` найденной сущности. При невозможности определить `ArticleType` или при незнакомом названии шаблона используется системный фолбэк (`"grid"`).
|
---
|
||||||
|
|
||||||
Полный список доступных видов отображения (`view_mode`) и поддерживаемых ими шаблонов ведет отдельно (в виде внешней документации компонентов либо будет добавлен ниже в этом документе по мере появления новых визуальных блоков).
|
### Составной режим отображения (`view_mode` + `limit` через `+`)
|
||||||
|
|
||||||
### Тип B: Динамический модуль / Плагин (Префикс `!`)
|
Позволяет вывести результаты одного SQL-запроса через комбинацию нескольких шаблонов (например, первые 2 элемента крупными тизерами, а остальные 15 элементов — компактным списком снизу) без дублирования блоков.
|
||||||
|
|
||||||
|
Синтаксис: `"teaser+list"`, `"2+15"`
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
- `["articles:type:info", "teaser+list", "2+15", "new+", {"title": "Инструкции и справка"}]`
|
||||||
|
- Выполняется 1 SQL-запрос с `LIMIT = 2 + 15 = 17`.
|
||||||
|
- Первые 2 статьи передаются в шаблон `teaser`.
|
||||||
|
- Следующие 15 статей передаются в шаблон `list`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Тип C: Динамический модуль / Плагин (Префикс `!`)
|
||||||
|
|
||||||
Запускает кастомный Python-модуль, зарегистрированный в системе (например, интерактивные виджеты, спецпредложения корзины, акции).
|
Запускает кастомный Python-модуль, зарегистрированный в системе (например, интерактивные виджеты, спецпредложения корзины, акции).
|
||||||
|
|
||||||
Формат: `[ "!module-slug", extra ]`
|
Формат: `[ "!module-slug", extra ]`
|
||||||
|
|
||||||
Отличительный признак: `slug` начинается с символа **`!`** (восклицательный знак). Так как знак `!` недопустим в обычных URL-слагах Django, парсер однозначно и безошибочно определяет, что данный блок является вызовом Python-плагина, а не поиском статьи/категории в БД.
|
Отличительный признак: `slug` начинается с символа **`!`** (восклицательный знак). Так как знак `!` недопустим в обычных URL-слагах Django, парсер однозначно и безошибочно определяет, что данный блок является вызовом Python-плагина.
|
||||||
|
|
||||||
Параметры:
|
|
||||||
|
|
||||||
1. `slug` (str, обязательный): Уникальный идентификатор с префиксом `!`, зарегистрированный в PluginRegistry (например, `!promo-mandarin`, `!cart-bonus`).
|
|
||||||
2. `extra` (dict, опциональный, default=`{}`): Словарь дополнительных параметров, передаваемых в модуль.
|
|
||||||
|
|
||||||
Пример:
|
Пример:
|
||||||
- `["!promo-mandarin"]`
|
- `["!promo-mandarin"]`
|
||||||
@@ -102,12 +156,12 @@
|
|||||||
{
|
{
|
||||||
"hub": [
|
"hub": [
|
||||||
["hero-cassettes-2026", "slider"],
|
["hero-cassettes-2026", "slider"],
|
||||||
["cassettes-studio", "carousel", 6, "views"],
|
["articles:type:info", "teaser+list", "2+15", "new+", {"title": "Инструкции и справочные материалы"}],
|
||||||
["cassettes-studio", "grid", 20, "newest"],
|
["offers:artist:the-beatles", "carousel", 10, "view+", {"title": "Релизы The Beatles в наличии"}],
|
||||||
|
["cassettes-studio", "carousel", 6, "view+"],
|
||||||
["!promo-mandarin"],
|
["!promo-mandarin"],
|
||||||
["cassettes-maxell-used-ud2-c90-ver2", "carousel", 6, "popular"],
|
["offers:format:vinyl", "grid", 20, "price+"],
|
||||||
["cassettes-tdk-ned-cding2-c60", "list", 20, "price_desc"],
|
["!cart-bonus", {"threshold": 5000}]
|
||||||
["guide-how-to-clean-heads", "teaser", 1]
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -124,10 +178,12 @@
|
|||||||
2. Ограничение глубины вложенности:
|
2. Ограничение глубины вложенности:
|
||||||
- Жестко ограничить максимальную глубину рекурсии: `MAX_RECURSION_DEPTH = 2` (устанавливается в `settings.py`).
|
- Жестко ограничить максимальную глубину рекурсии: `MAX_RECURSION_DEPTH = 2` (устанавливается в `settings.py`).
|
||||||
3. Отказоустойчивость (Graceful Degradation):
|
3. Отказоустойчивость (Graceful Degradation):
|
||||||
- Если `limit` передан не числом или `sort` содержит неизвестную строку, парсер должен тихо применить безопасные дефолты (автовыбор `view_mode` по `ArticleType` с фолбэком на `'grid'`, `limit=10`, `sort='newest'`). Ошибка синтаксиса в JSON никогда не должна приводить к `500 Server Error`.
|
- Если `limit` передан не числом или `sort` содержит неизвестную строку, парсер должен тихо применить безопасные дефолты (автовыбор `view_mode` по `ArticleType` с фолбэком на `'grid'`, `limit=10`, `sort='new+'`). Ошибка синтаксиса в JSON никогда не должна приводить к `500 Server Error`.
|
||||||
- Если `slug` (без `!`) не найден в базе, блок пропускается, а в HTML выводится комментарий: `<!-- DSL Error: Slug not found -->`.
|
- Если `slug` (без `!`) не найден в базе, блок пропускается, а в HTML выводится комментарий: `<!-- DSL Error: Slug not found -->`.
|
||||||
- Если модуль `!slug` не зарегистрирован в PluginRegistry, выводится комментарий: `<!-- DSL Error: Module not found -->`.
|
- Если модуль `!slug` не зарегистрирован в PluginRegistry, выводится комментарий: `<!-- DSL Error: Module not found -->`.
|
||||||
4. Изоляция данных:
|
4. Изоляция данных:
|
||||||
- Внутри DSL запрещено использовать сырые имена полей БД (например, k_offer_to_item__s_item). Все выборки данных маппятся строго через `slug` и внутренние обработчики запросов (Query Handlers).
|
- Внутри DSL запрещено использовать сырые имена полей БД (например, k_offer_to_item__s_item). Все выборки данных маппятся строго через `slug` и внутренние обработчики запросов (Query Handlers).
|
||||||
5. Валидация slug
|
5. Валидация slug
|
||||||
- Добавить в валидатор админки статей (TbArticle) проверку на несовпадение slug с существующими роутами сайта из `urls.py` (чтобы не было конфликта URL-ов).
|
- Добавить в валидатор админки статей (TbArticle) проверку на несовпадение slug с существующими роутами сайта из `urls.py` (чтобы не было конфликта URL-ов).
|
||||||
|
|
||||||
|
film0069t-2001.08.xx
|
||||||
Reference in New Issue
Block a user