Каждая страница любого сайта содержит свое содержимое и общие части — шапку, футер или боковое меню. И если с большим количеством однотипного кода страниц еще можно смириться, то настоящие сложности возникают при попытке изменить шаблоны. Легко случайно забыть внести изменения во все страницы. Чтобы избежать дублирования и потенциальных ошибок при изменениях однотипных страниц существует механизм наследования шаблонов. Мы можем создать базовый шаблон. Он будет содержать все общие элементы сайта и определять блоки, которые могут переопределять дочерние шаблоны.
Создадим новый шаблон layout.html со следующим содержимым:
<!-- courses/layout.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>{% block title %}Flask проект{% endblock %}</title>
</head>
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">Главная</a></li>
<li><a href="/courses/">Курсы</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
Этот шаблон определяет базовую структуру нашего сайта. Важная деталь в нем это конструкция {% block <имя-блока>%} {% endblock %}
. Во всех шаблонах-наследниках на место нее подставятся блоки с тем же именем из них.
Добавим новый шаблон-наследник:
<!-- courses/index.html -->
{% extends "courses/layout.html" %}
<!-- этот блок заменит блок title из родительского шаблона -->
{% block title %}Курсы{% endblock %}
<!-- этот блок заменит блок content из родительского шаблона -->
{% block content %}
<table>
{% for course in courses %}
<tr>
<td>
{{ course.id }}
</td>
<td>
{{ course.name }}
</td>
</tr>
{% endfor %}
</table>
{% endblock %}
Инструкция extends
сообщает шаблонизатору, что этот шаблон «расширяет» другой шаблон. Теперь, когда шаблонизатор будет обрабатывать наш шаблон index.html, инструкция extends
найдет родительский — layout.html. Далее она заменит в нем те блоки, которые мы переопределили в шаблоне index.html.
Поскольку в шаблоне index.html мы не используем блок sidebar
, вместо него будет использоваться значение из родительского шаблона. Содержимое внутри блока в родительском шаблоне всегда используется как значение по умолчанию.
В итоге, шаблон-наследник отрендерится так:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Курсы</title>
</head>
<body>
<div id="sidebar">
<ul>
<li><a href="/">Главная</a></li>
<li><a href="/courses/">Курсы</a></li>
</ul>
</div>
<div id="content">
<table>
<tr>
<td>
42
</td>
<td>
Курс по Flask
</td>
</tr>
</table>
</div>
</body>
</html>
Можно использовать столько уровней наследования, сколько необходимо. Один из распространенных способов использования наследования — трехуровневый подход:
- Создание layout.html шаблона, который содержит основной внешний вид сайта
- Создание layout_SECTIONNAME.html шаблонов для каждого раздела сайта, например, layout_course.html, layout_category.html. Эти шаблоны расширяют layout.html и включают в себя стили для конкретных разделов
- Создание отдельного шаблона для каждого типа страницы, например, курса или статьи. Эти шаблоны расширяют соответствующий шаблон раздела
Такой подход максимизирует повторное использование кода и помогает добавлять элементы в области общего содержимого, например, навигацию по всему разделу. Также любые измения в родительских шаблонах отразятся и на наследниках. Так мы можем быть уверены, что поправив заголовок в базовом шаблоне, поправим его и на всех других страницах.
Самостоятельная работа
- Повторите шаги из теории
Эталонное приложение
Дополнительные материалы
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.