Теги шаблонов Django: наследование и переопределение

Теги Django-шаблонов пишутся между конструкциями {% и %}.
Теги могут быть одиночные:
Скопировать кодHTML
{% include "footer.html" %}
или парные, из открывающего и закрывающего:
Скопировать кодHTML
{% block %} тело тега {% endblock %}
Возможны и более сложные варианты: например, у тега for есть вложенный тег empty. После имени тега могут идти параметры, например {% if variable %} ... {% endif %}. К параметрам можно применять фильтры {% if messages|length >= 100 %}.
Мы рассмотрим только те теги, которые вам понадобятся для выполнения заданий курса.
Создадим несложный шаблон и препарируем его:
Скопировать кодHTML
<!DOCTYPE html> <html> <head> <title>{% block title %}The Last Social Media You'll Ever Need{% endblock %} | Yatube</title> <link rel="stylesheet" href="style.css"> </head> <body> {% include "header.html" %} <nav id="sidebar"> {% block sidebar %} <ul> <li><a href="/">Главная</a></li> <li><a href="/about/">О сайте</a></li> <li><a href="/list/">Сообщения</a></li> </ul> {% endblock %} </nav> <div id="content"> {% block content %}Контент не подвезли :({% endblock %} </div> {% include "footer.html" %} </body> </html>
Обычно подобный шаблон сохраняется в файле base.html. Он предоставляет базовую структуру документа.

Тег block

Содержимое тега block может быть переопределено из другого шаблона. Если значение тега не переопределено, на страницу будет выведено значение, которое предустановлено в шаблоне (это значение может быть и пустым).
После названия тега block указывается его идентификатор: {% block title %}, {% block sidebar %} или {% block content %}. Идентификатор разработчик придумывает сам.

Тег extends

Одиночный тег extends сообщает системе, в каком шаблоне нужно переопределить блоки, описанные следом за этим тегом.
Например, если система вызывает какой-то шаблон и видит в нём тег extends "index.html", то в шаблоне indeх.html будут заменены все блоки, которые в вызванном шаблоне перечислены по именам после тега {% extends "index.html" %}.
Создадим шаблон list.html, который переопределит блоки title, sidebar и content в шаблоне base.html.
Скопировать кодHTML
{% extends "base.html" %} {% block title %}Список сообщений{% endblock %} {% block sidebar %} <ul> <li><a href="/">Главная</a></li> <li><a href="/about/">О сайте</a></li> <li><a href="/list/" class="active">Сообщения</a></li> </ul> {% endblock %} {% block content %} {% for msg in messages %} <h2>{{ msg.title }}, от {{ msg.from }}</h2> <p>{{ msg.body }}</p> {% endfor %} {% endblock %}
Теперь из view-функции можно вызвать шаблон list.html, передать в него список messages с объектами сообщений (со свойствами title, from, body) — и сервер вернёт HTML-страницу с кодом из шаблона base.html, но с контентом, сгенерированным в файле list.html. То есть будет установлен <title> «Список сообщений», в сайдбаре будет подсвечен пункт меню «Сообщения», а в блок content — выведен список самих сообщений.
Пользователю будет возвращена страница list.html, в которой весь код будет из base.html, а содержимое блоков — из list.html.

Тег include

Этот тег по своей задаче — антипод тега extend.
Он включает в код шаблона содержимое другого шаблона. Вот простенький файл index.html:
Скопировать кодHTML
<!DOCTYPE html> <html> <head> <title>The Last Social Media You'll Ever Need | Yatube</title> <link rel="stylesheet" href="style.css"> </head> <body> {% include "header.html" %} <nav id="sidebar"> <ul> <li><a href="/">Главная</a></li> <li><a href="/about/">О сайте</a></li> <li><a href="/list/">Сообщения</a></li> </ul> </nav> <div id="content"> Контент страницы </div> {% include "footer.html" %} </body> </html>
В той же директории, где сохранён index.html, лежат ещё два файла:
файл header.html
Скопировать кодHTML
<div id="top-of-site"> {# здесь описана шапка сайта, она повторяется на всех страницах проекта #} <img src="images/logo.jpg" alt="Yatube" /> <div id="site-name">Yatube</div> </div>
файл footer.html
Скопировать кодHTML
<div id="bottom-of-site"> {# здесь описан подвал сайта, он одинаковый на всех страницах проекта #} <img src="images/logo.jpg" alt="Yatube" /> Yatube <div id="copyright">© Все права принадлежат всем</div> </div>
В результате обработки шаблона index.html на место тегов {% include "header.html" %} и {% include "footer.html" %} будет вставлен код из соответствующих файлов.
В тег include можно передать дополнительные параметры. Например, для вывода контактов можно создать шаблон card.html:
Скопировать кодHTML
<div class="card"> {{ name }} <br> <a href="mailto:{{ email }}">Отправить сообщение</a> </div>
При включении в шаблон user.html передаём в код шаблона card.html нужные данные:
Скопировать кодHTML
<!DOCTYPE html> <html> <head> <title>Иван Васильевич | Yatube</title> <link rel="stylesheet" href="style.css"> </head> <body> {% include "header.html" %} <nav id="sidebar"> <ul> <li><a href="/">Главная</a></li> <li><a href="/about/">О сайте</a></li> <li><a href="/list/">Сообщения</a></li> </ul> </nav> <div id="content"> {% include "card.html" with name="Иван Васильевич" email="iv@example.com" %} {# а можно сделать иначе: передать значения переменных #} {% include "card.html" with name=user.name email=user.mail %} </div> {% include "footer.html" %} </body> </html>