Метки в шаблонах документов
Система рендерит акты и журналы по .docx/.dotx-шаблонам. В тексте шаблона расставляются метки в фигурных скобках, которые при формировании документа подменяются на реальные значения из БД.
Синтаксис меток — Jinja2 через библиотеку docxtpl (официальная дока).
Базовый синтаксис
| Что | Как написать в шаблоне |
|---|---|
| Подставить значение | {{ order.number }} |
| Условный блок (если поле пустое — скрыть фразу) | {% if order.description %}Описание: {{ order.description }}{% endif %} |
| Условный блок без пустого абзаца (рекомендуется) | {%p if customer.kpp %}КПП: {{ customer.kpp }}{%p endif %} |
| Цикл по списку (например внутри таблицы) | {%tr for item in items %}…{%tr endfor %} |
⚠️ Важно: набирай метки вручную с клавиатуры, не вставляй через копипаст из браузера или PDF. Word может разрезать {{ и }} на разные текстовые «run»-блоки внутри XML, и docxtpl потеряет границы метки.
Словарь для актов заявок
Доступно в шаблонах, которые привязаны к типам заявок (Справочники → Виды заявок).
order.* — данные заявки
| Метка | Значение | Пример |
|---|---|---|
{{ order.number }} |
Номер заявки | 2026-001 |
{{ order.created_at }} |
Дата создания | 07.06.2026 |
{{ order.description }} |
Описание / задание | Заменить датчик дыма |
contract.* — договор
| Метка | Значение | Пример |
|---|---|---|
{{ contract.number }} |
Номер договора | 12/2026-ТО |
{{ contract.date_of_consclusion }} |
Дата заключения | 01.06.2026 |
{{ contract.date_of_completion }} |
Дата завершения | 31.12.2026 |
{{ contract.subject }} |
Полный предмет договора | Техническое обслуживание систем АПС... |
{{ contract.short_subject }} |
Краткое название | ТО АПС |
customer.* — заказчик
| Метка | Значение | Пример |
|---|---|---|
{{ customer.name }} |
Полное наименование | Общество с ограниченной ответственностью «Ромашка» |
{{ customer.short_name }} |
Короткое название | ООО «Ромашка» |
{{ customer.inn }} |
ИНН | 7701234567 |
{{ customer.kpp }} |
КПП | 770101001 |
{{ customer.director_full_name }} |
Директор в формате И.И. Иванов | И.И. Иванов |
{{ customer.address }} |
Юр. адрес одной строкой | 101000, г. Москва, ул. ..., д. 1 |
executor.* — исполнитель
Поля идентичны customer.* — {{ executor.name }}, {{ executor.inn }} и т.д.
object.* — объект (где будут работы)
| Метка | Значение | Пример |
|---|---|---|
{{ object.name }} |
Название объекта | Бизнес-центр «Альфа» |
{{ object.address }} |
Адрес объекта | 101000, г. Москва, ул. ..., д. 5 |
{{ object.responsible_face }} |
Ответственное лицо на объекте | Петров П.П. |
{{ object.responsible_faces_contact }} |
Контакт ответственного | +7 (495) 123-45-67 |
user.* — пользователь, который формирует акт
| Метка | Значение | Пример |
|---|---|---|
{{ user.full_name }} |
ФИО | Сидоров С.С. |
{{ user.role_name }} |
Роль | Инженер ТО |
qr — QR-код заявки для мобильного приложения
| Метка | Значение | Пример |
|---|---|---|
{{ qr }} |
Картинка QR-кода со ссылкой на эту заявку в приложении AutoReport (~3×3 см) | (в акте появится квадратный QR-код) |
Инженер сканирует QR камерой из мобильного приложения (кнопка 📷 в шапке главного экрана) и попадает сразу в карточку заявки — не нужно искать её вручную.
Куда поставить в шаблоне. Куда угодно — в шапке рядом с номером, в конце после подписей, в ячейке таблицы. Достаточно вставить {{ qr }} в нужное место.
Если хотите подпись рядом с QR — напишите её текстом в шаблоне, например:
{{ qr }}
Сканируйте QR-код в мобильном приложении AutoReport
Если в шаблоне метки {{ qr }} нет — QR в акт не попадёт (старые шаблоны продолжают работать как раньше).
Даты сегодня
| Метка | Значение | Пример |
|---|---|---|
{{ today }} |
Короткий формат | 13.06.2026 |
{{ today_long }} |
Полный формат | «13» июня 2026 г. |
equipment_groups — оборудование объекта, сгруппированное по системам
Список разделов, каждый — это тип обслуживаемой системы (spec_system) и список единиц оборудования внутри.
Структура одного элемента списка:
{
"index": 1,
"system_name": "Система пожарной сигнализации",
"rows": [
{ "index": "1.1", "name": "Извещатель ИП-212-89", "count": 12 },
{ "index": "1.2", "name": "Прибор приёмно-контрольный С2000", "count": 1 }
]
}
Оборудование без привязки к spec_system попадает в отдельный финальный раздел с system_name="Оборудование".
Как нарисовать такую таблицу в Word — см. ниже («Таблицы в актах»).
Таблицы в актах
docxtpl поддерживает циклы по строкам Word-таблиц через специальный синтаксис {%tr ... %}. Для двухуровневой таблицы (раздел → строки оборудования) используется вложенный цикл.
⚠️ Главное правило {%tr%}-разметки
В docxtpl 0.20.x строки с {%tr%}-тегами удаляются целиком. То есть {%tr for %} и {%tr endfor %} — это строки-маркеры: они исчезают из готового документа, превращаясь в обёртку {% for %}...{% endfor %} вокруг соседних строк.
Поэтому строку-маркер нельзя совмещать со строкой данных. Каждый {%tr for %} и {%tr endfor %} живёт в отдельной строке таблицы без данных, а строка(-и) с {{ ... }} — между ними.
Если положить {%tr for x in items %} в ту же строку, где {{ x.name }} — эта строка удалится вместе с данными, и цикл прокрутится «вхолостую» (таблица останется пустой). Это самый частый источник недоумения.
Простая таблица (одноуровневая)
Структура из 3 строк + шапка:
| Строка | Ячейка 1 | Ячейка 2 |
|---|---|---|
| 0 — шапка | № | Наименование |
| 1 — маркер начала | {%tr for row in some_list %} |
(пусто) |
| 2 — шаблон строки данных | {{ row.index }} |
{{ row.name }} |
| 3 — маркер конца | {%tr endfor %} |
(пусто) |
При рендере строки 1 и 3 удалятся; строка 2 размножится по числу элементов в some_list.
Двухуровневая таблица: разделы + оборудование
Для актов ТО — заголовок раздела (название системы) и под ним список оборудования. Структура 7 строк (шапка + 4 строки-маркера + 2 строки-шаблоны):
| Строка | Ячейка 1 | Ячейка 2 | Ячейка 3 |
|---|---|---|---|
| 0 — шапка | № | Наименование | Кол-во |
| 1 — маркер: открыть внешний цикл | {%tr for group in equipment_groups %} |
— | — |
| 2 — section row (жирным) | {{ group.index }}. |
{{ group.system_name }} |
— |
| 3 — маркер: открыть внутренний цикл | {%tr for row in group.rows %} |
— | — |
| 4 — item row | {{ row.index }} |
{{ row.name }} |
{{ row.count }} |
| 5 — маркер: закрыть внутренний цикл | {%tr endfor %} |
— | — |
| 6 — маркер: закрыть внешний цикл | {%tr endfor %} |
— | — |
При рендере строки 1, 3, 5, 6 исчезают. Строка 2 повторяется по числу групп; строка 4 — по числу элементов внутри текущей группы.
⚠️ Важно:
- Обе пары
{%tr for %}/{%tr endfor %}— в одной Word-таблице. Если разнести по разным таблицам — циклы не свяжутся. - В одной ячейке нельзя совмещать
{%tr endfor %}{%tr endfor %}— это закроет только один цикл (для одной строки), второй останется буквальным текстом и Jinja упадёт сEncountered unknown tag 'endfor'. Каждомуendfor— своя строка. - Объединение ячеек (merge) в section-row иногда ломает повтор у docxtpl. Если видишь пустую таблицу, проверь сначала без merge.
- Внутренний
{%tr for row in group.rows %}использует переменнуюgroupиз внешнего цикла — это нормальное вложение Jinja. - Жирность и форматирование делаются обычным Word-инструментом, docxtpl сохраняет их.
Готовый образец
В репозитории бэка есть генерируемый референс templates/blanks/example_two_level.docx (в git не закоммичен — лежит локально для отладки). Скрипт его создания — в истории чатов; при потребности можно перегенерировать через python-docx.
Если нужен плоский список без разделов
Вариант: вложенные {%tr%} оставляешь, но в section-строке не выводишь ничего из group. Тогда получишь просто список оборудования подряд.
Прямой плоский цикл одной строкой типа {%tr for group in equipment_groups %}{%tr for row in group.rows %} в одной ячейке не сработает — каждый {%tr%} применяется ко всей строке целиком, и два цикла на одной строке конфликтуют.
Условные блоки в таблицах
Если хочешь скрыть пустую секцию (когда group.rows пуст), на строке-маркере открытия внешнего цикла:
{%tr for group in equipment_groups if group.rows %}
Это валидный Jinja-синтаксис, docxtpl его поддерживает.
Словарь для журналов объектов
Доступно в шаблонах, которые привязаны к видам журналов (Справочники → Виды журналов).
Тот же набор кроме user.* и order.* — журналы привязаны к объекту, а не к заявке:
{{ object.* }}— все поля{{ contract.* }}— все поля{{ customer.* }}и{{ executor.* }}— все поля{{ today }},{{ today_long }}
Примеры шаблонных фраз
Шапка акта
АКТ № {{ order.number }} от {{ today_long }}
Исполнитель: {{ executor.name }}, ИНН {{ executor.inn }}
в лице директора {{ executor.director_full_name }},
действующего на основании Устава,
с одной стороны,
и
Заказчик: {{ customer.name }}, ИНН {{ customer.inn }}
в лице директора {{ customer.director_full_name }},
действующего на основании Устава,
с другой стороны,
составили настоящий акт о следующем:
Условный блок (показать строку только если поле заполнено)
{%p if customer.kpp %}КПП: {{ customer.kpp }}{%p endif %}
Если у заказчика не указан КПП — вся эта строка (вместе с абзацем) полностью исчезнет из готового документа. Если указан — появится «КПП: 770101001».
Подпись
От Исполнителя: От Заказчика:
____________________ ____________________
{{ executor.director_full_name }} {{ customer.director_full_name }}
М.П. М.П.
Документ сформировал: {{ user.full_name }} ({{ user.role_name }})
Дата: {{ today }}
Связано
- См. статью «Загрузка и редактирование шаблонов» — про процесс заливки готового шаблона в систему.