Перейти к содержанию

Взаимодействие шаблонов

В прошлом уроке мы познакомились с основными возможностями шаблонов. Теперь переключимся на возможности шаблонов взаимодействовать друг с другом.

Способы связать разные шаблоны друг с другом:

  • Через тег вставки одного шаблона в другой {% include "template.html" %}
  • Через наследование и блоки
  • С помощью макросов

Вставки

Это самый простой способ. Если у вас есть какой-то HTML блок, который часто повторяется, или вы хотите разбить шаблон на логические куски, то можно использовать конструкцию вставки.

Представим, что у нас есть шаблон footer.html:

<!-- Это подвал сайта -->
<div id="footer">
   <img src="/static/images/footer-logo.jpg" alt="Logo" /> Сайт компании друзей
    <div id="copyright">© Все права принадлежат нам</div>
</div>

Теперь если в другом шаблоне можно сделать вставку этого подвала:

<!DOCTYPE html>
<html>
<head>
    <title>Заголовок страницы</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>    
    <div id="content">
        Контент страницы
    </div>
    {% include "footer.html" %}
</body>
</html>

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

{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" with context %}
{% include "sidebar.html" ignore missing without context %}

Построчный разбор примера:

  • Если файл не будет найден, то не будет сформирована ошибка
  • В шаблон передается контекст, а значит там будут доступны все переменные шаблона
  • Комбинированный случай, когда игнорируется отсутствующий файл, а если есть, то в него не передаются отсутствующие переменные

Если вы не уверены, что файл существует, и если его нет, то надо найти следующий то, Jinja поддерживает синтаксис поиска по списку:

{% include ['page_detailed.html', 'page.html'] %}
{% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}

Наследование шаблонов и блоки

Обычно проекты содержат много похожих страниц. У всех есть заголовок, есть подвал, есть правая или левая навигация. Но довольно часто надо гибко использовать шаблон, например при необходимости выводить или не выводить определенный блок. Для того чтобы не повторять однотипные задачи шаблоны поддерживают наследование.

Пример базового шаблона сайта. Обычно в своих проектах я его называю base.html:

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}{{ page_title|default('New page') }}{% endblock %}</title>
    <link rel="stylesheet" href="/static/style.css">
    {% block include_css %}
    {% endblock %}
    {% block html_header %}
    {% endblock %}
</head>

<body {% block body_id %}{% endblock %}>
    {% include "header.html" %}
    {% include "nav.html" %}

    {% block content %}
    <div id="content">
        Контент страницы
    </div>
    {% endblock %}
    {% include "footer.html" %}
</body>
</html>

Этот файл содержит блоки, которые описаны с помощью тегов {% block <name> %} и заканчиваются {% endblock %} можно наследоваться от этого шаблона и переопределить содержимое этих блоков. Для того чтобы шаблон наследовался от другого он должен начинаться с выражения {% extends "<template>" %}

Например, этот шаблон page.html выводит простую текстовую страницу:

{% extends "base.html" %}
{% set page_title = page.title %}

{% block content %}

{{ page.html|safe }}

{% endblock %}

И теперь его можно вызвать из кода:

@app.route('/docs/<page_name>/', endpoint='page')
def page(page_name):
    """Просмотр страниц"""
    # Pages view
    _page = pages.get_or_404(page_name)
    return render_template('page.html', page=_page)

Макросы

Макросы напоминают работу модулей в Python, только вместо функций вы можете импортировать Jinja макросы.

Пример файла с библиотекой макросов macros.html:

{% macro big_header(text) %}
  <h1 class="big">{{ text }}</h1>
{% endmacro %}

{% macro sub_header(text) %}
  <h2 class="subheader">{{ text }}</h2>
{% endmacro %}

Теперь если понадобится в каком-то и шаблонов вызывать код отображающий большой заголовок, то можно его импортировать:

{% import 'macros.html' as headers %}

{{ headers.big_header("Добро пожаловать!") }}

Или можно указать конкретный макрос:

{% from 'macros.html' import big_header as big  %}

{{ big("Добро пожаловать!") }}

Макросы тоже поддерживают возможность или запрет передачи контекста внутрь:

{% from 'forms.html' import input with context %}
{% include 'header.html' without context %}