From 3ce721451558b213012596caffb26535703f75da Mon Sep 17 00:00:00 2001 From: erjemin Date: Sat, 8 Aug 2026 22:13:07 +0300 Subject: [PATCH] =?UTF-8?q?mod:=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20DSL=20+=20=D1=81=D0=B8=D0=BD=D1=82=D0=B0=D0=BA?= =?UTF-8?q?=D1=81=D0=B8=D1=81=20=D0=B4=D0=BB=D1=8F=20=D1=84=D0=B8=D0=BB?= =?UTF-8?q?=D1=8C=D1=82=D1=80=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B8=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=B1=D0=B8=D0=BD=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=BD=D1=8B=D1=85=20=D0=B1=D0=BB=D0=BE=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _prj_blueprint/DSL.md | 140 +++++++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 42 deletions(-) diff --git a/_prj_blueprint/DSL.md b/_prj_blueprint/DSL.md index a61d17f..7c74ca2 100644 --- a/_prj_blueprint/DSL.md +++ b/_prj_blueprint/DSL.md @@ -19,10 +19,31 @@ ## 2. Синтаксис и структура JSON DSL -Массив `hub` представляет собой список позиционных кортежей (массивов). Порядок элементов в кортеже фиксирован, при этом все элементы, кроме первого (`slug`), являются опциональными. +Массив `hub` представляет собой список позиционных кортежей (массивов). Порядок элементов в кортеже строго фиксирован. Все элементы, кроме первого (`slug` / `source`), являются опциональными и имеют безопасные значения по умолчанию. Позиционный порядок параметров: `[ "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 @@ -32,6 +53,7 @@ ["source-slug", "view_mode", limit], ["source-slug", "view_mode", limit, "sort_rule"], ["source-slug", "view_mode", limit, "sort_rule", {"title": "Кастомный заголовок"}], + ["articles:type:info", "teaser+list", "2+15", "new+"], ["!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 ]` -Параметры (позиционные): +Примеры: +- `["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` → Горизонтальная карусель / слайдер. - - `grid` → Стандартная сетка карточек. - - `list` → Компактный вертикальный список. - - `teaser` → Тизер статьи с кнопкой «Читать далее». - - `full` → Полный HTML-контент статьи, встроенный inline. - - *Примечание:* Если `view_mode` не указан, шаблон выбирается автоматически в соответствии с типом сущности (`ArticleType` модели `TbArticle`), за которой закреплен слаг. У каждого `ArticleType` есть свой дефолтный шаблон. -3. `limit` (int, опциональный, default=`10`): Количество выводимых элементов (например, 5, 20). -4. `sort` (str, опциональный, default=`"newest"`): Правило сортировки: - - `newest` → -t_offer_created (новинки) - - `views` → -i_offer_views (самые просматриваемые) - - `favorites` → -i_offer_favorites (самые популярные / в избранном) - - `price_asc` → f_offer_price (сначала дешевые) - - `price_desc` → -f_offer_price (сначала дорогие) -5. `extra` (dict, опциональный, default=`{}`): Дополнительные произвольные настройки блока (например, `{"title": "Переопределенный заголовок"}`). +--- + +### Тип B: Динамическая выборка / Запрос к БД (Префикс с двоеточием `:`) + +Позволяет формировать динамические списки офферов (`offers:...`) или статей (`articles:...`) по заданным критериям без создания отдельных вьюх. + +Формат источника (`source`): +- `offers:artist:` — офферы конкретного исполнителя (например, `offers:artist:the-beatles`) +- `offers:format:` — офферы конкретного формата (например, `offers:format:vinyl`) +- `offers:style:` — офферы музыкального стиля (например, `offers:style:jazz`) +- `articles:type:` — статьи определенного типа `ArticleType` (например, `articles:type:info`, `articles:type:blog`) +- `articles:artist:` — статьи, связанные с исполнителем (например, `articles:artist:the-beatles`) Примеры: -- `["cassettes-studio"]` — подборка кассет (дефолтные view_mode по `ArticleType`, limit=10, sort="newest") -- `["cassettes-studio", "carousel"]` — карусель студийных кассет (дефолтные limit=10, sort="newest") -- `["cassettes-studio", "carousel", 6]` — карусель из 6 студийных кассет -- `["cassettes-studio", "carousel", 6, "views"]` — 6 самых просматриваемых кассет в карусели -- `["cassettes-studio", "carousel", 6, "views", {"title": "Хиты продаж"}]` — с переопределенным заголовком +- `["articles:type:info", "list", 50]` — до 50 статей типа `INFO` в виде списка +- `["offers:artist:the-beatles", "carousel", 10, "view+"]` — 10 популярных релизов The Beatles в карусели -Замечания: `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-модуль, зарегистрированный в системе (например, интерактивные виджеты, спецпредложения корзины, акции). Формат: `[ "!module-slug", extra ]` -Отличительный признак: `slug` начинается с символа **`!`** (восклицательный знак). Так как знак `!` недопустим в обычных URL-слагах Django, парсер однозначно и безошибочно определяет, что данный блок является вызовом Python-плагина, а не поиском статьи/категории в БД. - -Параметры: - -1. `slug` (str, обязательный): Уникальный идентификатор с префиксом `!`, зарегистрированный в PluginRegistry (например, `!promo-mandarin`, `!cart-bonus`). -2. `extra` (dict, опциональный, default=`{}`): Словарь дополнительных параметров, передаваемых в модуль. +Отличительный признак: `slug` начинается с символа **`!`** (восклицательный знак). Так как знак `!` недопустим в обычных URL-слагах Django, парсер однозначно и безошибочно определяет, что данный блок является вызовом Python-плагина. Пример: - `["!promo-mandarin"]` @@ -102,12 +156,12 @@ { "hub": [ ["hero-cassettes-2026", "slider"], - ["cassettes-studio", "carousel", 6, "views"], - ["cassettes-studio", "grid", 20, "newest"], + ["articles:type:info", "teaser+list", "2+15", "new+", {"title": "Инструкции и справочные материалы"}], + ["offers:artist:the-beatles", "carousel", 10, "view+", {"title": "Релизы The Beatles в наличии"}], + ["cassettes-studio", "carousel", 6, "view+"], ["!promo-mandarin"], - ["cassettes-maxell-used-ud2-c90-ver2", "carousel", 6, "popular"], - ["cassettes-tdk-ned-cding2-c60", "list", 20, "price_desc"], - ["guide-how-to-clean-heads", "teaser", 1] + ["offers:format:vinyl", "grid", 20, "price+"], + ["!cart-bonus", {"threshold": 5000}] ] } ``` @@ -124,10 +178,12 @@ 2. Ограничение глубины вложенности: - Жестко ограничить максимальную глубину рекурсии: `MAX_RECURSION_DEPTH = 2` (устанавливается в `settings.py`). 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 выводится комментарий: ``. - Если модуль `!slug` не зарегистрирован в PluginRegistry, выводится комментарий: ``. 4. Изоляция данных: - Внутри DSL запрещено использовать сырые имена полей БД (например, k_offer_to_item__s_item). Все выборки данных маппятся строго через `slug` и внутренние обработчики запросов (Query Handlers). 5. Валидация slug - - Добавить в валидатор админки статей (TbArticle) проверку на несовпадение slug с существующими роутами сайта из `urls.py` (чтобы не было конфликта URL-ов). \ No newline at end of file + - Добавить в валидатор админки статей (TbArticle) проверку на несовпадение slug с существующими роутами сайта из `urls.py` (чтобы не было конфликта URL-ов). + +film0069t-2001.08.xx \ No newline at end of file