Документация шаблонизатора

Базовый синтаксис

Наш шаблонизатор использует минимальный синтаксис для выполнения Вашей работы.
Шаблонизатор построен на движке Jinja2, который имеет огромные возможности кастомизации.
Давайте начнем с основ и перейдем к более сложным сценариям.

Предположим, у нас есть простой объект данных, который мы хотим применить к нашему шаблону.
JSON-представление объекта:

{
    "name": "Петр Иванович"
}
                               
И мы хотим включить имя в сгенерированный документ.
Нам нужно окружить свойство фигурными скобками. Слева - шаблон, справа - результат:

Здравствуйте {{ name }}

Здравствуйте Петр Иванович

Работа с переменными

Двойные фигурные скобки {{ }} позволяют получить результат выражения или переменной и вывести значение в шаблоне.

{{ 10 + 5 }}
{{ 10 / 3 }}
{{ 10 // 3}}
{{ 10 % 3 }}
{{ 10 ** 3 }}

15
3.3333333333333335
3
1
1000

JSON-представление объекта:

{
    "fruit": "Яблоко",
    "price": 50"
}
                               

{{ fruit }} стоит {{ price }} рублей.

Яблоко стоит 50 рублей.

Внутри Вашего шаблона, можно определить переменные, для хранения часто используемых значений.
Или необходимо сохранить что-либо для использования позднее. Вместо написания значения каждый раз, используем переменную. Переменные, определенные вне управляющих конструкций, ведут себя как глобальные переменные, и доступны из любого места. Переменные, созданные внутри конструкций, ведут себя как локальные переменные, и видимы только внутри этих конкретных конструкций.

{% set name = 'Иван Петрович' %}
Здравствуйте {{ name }}

Здравствуйте Петр Иванович

Можно объявить сразу несколько переменных, в одной строке.

{% set name, surname = 'Иван', 'Петрович' %}
Здравствуйте {{ name }} {{ surname }}

Здравствуйте Петр Иванович

Циклы и управляющие конструкции

Управляющие конструкции позволяют добавлять в шаблоны элементы управления потоком и циклы.
По умолчанию, управляющие конструкции используют разделитель {% %} вместо двойных фигурных скобок {{ }}.

Конструкция if, elif и else

Для понимания работы, давайте сразу рассмотрим несколько примеров.

JSON-представление объекта:

{
    "name": "Петр Иванович",
    "age": 45
}
                               

{% if name == 'Петр Иванович' and age == 15 %}
    Совсем Вы молодой {{ name }}, Вам всего {{ age }} лет.
{% elif name == 'Петр Иванович' and age == 25 %}
    Ну уже постарше. {{ name }}, Вам всего {{ age }} лет.
{% elif name == 'Петр Иванович' and age == 45 %}
    Отлично! Мы узнали, что Вам {{ name }}, уже {{ age }} лет.
{% else %}
    Я Вас не знаю, и знать не хочу.
{% endif %}

Отлично! Мы узнали, что Вам Петр Иванович, уже 45 лет.

В первой строке проверяется, если переменная "name" равна строке "Петр Иванович",
и переменная "age" равно числу 45, то выполнится блок:

Совсем Вы молодой Петр Иванович, Вам всего 45 лет.

Если первое условие не выполняется, то благодаря оператору "elif", проверяем следующее условие, аналогично первому.
В случае, если не выполняется, ни одно из условий, то будет выполнен блок в операторе "else".

Я Вас не знаю, и знать не хочу.

Управляющие инструкции также могут быть вложенными.

{% if name == 'Петр Иванович' %}
    {% if age == 15 %}
        Совсем Вы молодой {{ name }}, Вам всего {{ age }} лет.
    {% else %}
         Да, да! Вам {{ name }}, уже не 15 лет!
    {% endif %}
{% endif %}

Да, да! Вам Петр Иванович, уже не 15 лет!

Если условия становятся слишком сложными, можно обернуть выражения скобками ():

{% if (age > 15) and (age =< 45) %}
     Здравствуйте, Петр Иванович. Мы вас узнали.
{% endif %}
{% if (name == 'Дмитрий Николаевич') or (name == 'Иван Иванович') %}
     Привет, Дмитрий или Иван!
{% endif %}

Здравствуйте, Петр Иванович. Мы вас узнали.

Цикл for

Цикл for позволяет перебирать последовательность.

JSON-представление объекта:

{
    "name": "Петр Иванович",
    "fruits": {
        "loves": ["Яблоки", "Апельсины"],
        "not_loves": ["Груши", "Ананасы", "Киви"]
    }
}
                               

Цикл можно проходить не только по массиву, но и по словарю.

JSON-представление объекта:

{
  "name": "Петр Иванович",
  "age": 45,
  "about": "Хороший человек"
}
                               

Вы не поверите, но той информации, что Вы уже узнали, хватит, что-бы создать динамически наполняемую таблицу.
Рассмотрим пример.

JSON-представление объекта:

{
    "col_labels": ["Фрукты", "Овощи", "Камни", "Мебель"],
    "tbl_contents": [
        {"cols": ["банан", "перец", "пирит", "стул"]},
        {"cols": ["яблоко", "помидор", "алмаз", "стол"]},
        {"cols": ["апельсин", "картошка", "янтарь", "кровать"]}
    ]
}
                               

Конструкция {% colspan <переменная> %} должна быть обязательно.
Для динамического распределения по множеству столбцов.
В документе она не учитывается, и нужна только в шаблоне.

Конструкция {{ loop.index }}, внутри цикла for начинает отсчет с 1.

В таблице упомянуты остальные широко используемые атрибуты переменной loop.

МетодЗначение
1loop.index0Тоже самое что и loop.index, но с индексом 0, то есть, начинает считать с 0, а не с 1.
2loop.revindexВозвращает номер итерации с конца цикла (считает с 1).
3loop.revindex0Возвращает номер итерации с конца цикла (считает с 0).
4loop.firstВозвращает True, если итерация первая. В противном случае — False.
5loop.firstВозвращает True, если итерация последняя. В противном случае — False.
6loop.firstВозвращает длину цикла(количество итераций).

Давайте рассмотрим еще один пример. Сделаем форму заказа товаров.

JSON-представление объекта:

{
    "customer_name": "Иван",
    "items": [
        {"desc": "Апельсины", "qty": 2, "price": "Бесплатно"},
        {"desc": "Мандарины", "qty": 5403, "price": "500,000"},
        {"desc": "Киви", "qty": 1, "price": "100,000,000.00"}
    ],
    "in_europe": true,
    "is_paid": false,
    "company_name": "PRINTDOC",
    "total_price": "100,000,000.00"
}
                               

Фильтры

Фильтры изменяют переменные до процесса преобразования шаблона в документ.
Синтаксис использования фильтров следующий:
variable_or_value|filter_name
Рассмотрим на примере:

{% set name = 'иван петрович' %}
Здравствуйте {{ name|title }}

Здравствуйте Иван Петрович

Фильтр title делает заглавной первую букву в каждом слове.
Если значение - "иван петрович", то вывод после использования фильтра будет "Иван Петрович".

Можно использовать несколько фильтров, чтобы точнее настраивать вывод. Например:

{{ full_name|striptags|title }}

Фильтр striptags удалит из переменной все HTML-теги.
В приведенном выше коде сначала будет применен фильтр striptags, а затем — title.

У некоторых фильтров есть аргументы.
Чтобы передать их фильтру, нужно вызвать фильтр как функцию.
Например: {{ number|round(2) }}

Фильтр round округляет число до конкретного количества символов.
В следующей таблице указаны широко используемые фильтры.

НазваниеОписание
1upperПриводит все строковые символы в верхнему регистру.
2lowerПриводит все строковые символы в нижнему регистру.
3capitalizeДелает заглавной первую букву и приводит остальные к нижнему регистру.
4lengthВозвращает количество элементов в массиве.
5trimУдаляет пустые символы в начале и в конце строки.
6randomВозвращает случайный элемент последовательности.

Теги

Для управления абзацами, строками таблицы, столбцами таблицы, оформлением строк должен использоваться специальный синтаксис.

{%p jinja2_tag %} - для параграфов
{%tr jinja2_tag %} - для строк в таблицах
{%tc jinja2_tag %} - для колонок в таблицах
{%r jinja2_tag %} - для оформления строк

ВАЖНО: Не используйте {%p, {%tr, {%tc или {%r два раза в том же параграфе, строке или столбце. Пример:

Неправильно:

{%p if display_paragraph %} Это мой параграф {%p endif %}

Правильно:

{%p if display_paragraph %}
Это мой параграф
{%p endif %}

ВАЖНО: Используйте неразрывный пробел ( CTRL + SHIFT + ПРОБЕЛ ), когда требуется пробел в начале или в конце строки.

ВАЖНО: Теги должны располагаться отдельно в строке: не добавляйте текст до или после в той же строке.

ВАЖНО: Всегда ставьте пробел после начального разделителя переменных / тегов

Неправильно:

{{myvariable}}
{%if something%}

Правильно:

{{ myvariable }}
{% if something %}

Цвет ячейки

Есть особый случай, когда вы хотите изменить цвет фона ячейки таблицы, вы должны поместить следующий тег в самое начало ячейки:

{% cellbg <переменная> %}

Колонки динамической таблицы

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

{% colspan <переменная> %}

Отображение зарезервированных символов

Для того, чтобы отобразить {%, %}, {{ или }} , можно использовать:

{_%, %_}, {_{ или }_}

Таблицы

Вы можете растянуть ячейки таблицы по горизонтали двумя способами, используя colspan (см. шаблон: dynamic_table_tpl.docx):

{% colspan <количество колонок> %}

или внутри цикла for (см. шаблон: horizontal_merge_tpl):

{% hm %}

Вы также можете объединять ячейки по вертикали в цикле for (см. шаблон: vertical_merge_tpl.docx):

{% vm %}

Более подробное описание функционала шаблонизатора, Вы можете найти на официальном сайте Jinja2.

Лучший способ увидеть, как это работает - скачать, и посмотреть примеры.
*.docx файлы - код шаблона и готовый результат (как в документе).
*.json файлы - json код, для передачи в шаблон.

ШаблонJSON
1vertical_merge_tpl.docxВстроен в файл шаблона.
2vertical_merge_nested_tpl.docxВстроен в файл шаблона.
3nested_for_tpl.docxnested_for_tpl.json
4less_cells_after_loop_tpl.docxВстроен в файл шаблона.
5horizontal_merge_tpl.docxВстроен в файл шаблона.
6cellbg_tpl.docxcellbg_tpl.json
7order_tpl.docxorder_tpl.json
8dynamic_table_tpl.docxdynamic_table_tpl.json
9header_footer_entities_tpl.docxheader_footer_entities_tpl.json