MyTetra Share
Делитесь знаниями!
Шаблоны extends
Время создания: 04.01.2018 02:58
Раздел: Django
Запись: xintrea/mytetra_db_mcold/master/base/1515023883n7epqgs5yl/text.html на raw.githubusercontent.com

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

Пред. 

Глава 4. Шаблоны

 След.


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

До этого момента наши примеры шаблонов содержали крошечные фрагменты HTML, но в реальном проекте, вы будете использовать шаблонную систему Django для создания всех страниц проекта. Это приводит к общей проблеме веб разработки — рассматривая весь сайт, как уменьшить повторение и избыточность общих областей страниц, таких как навигация по сайту?

Классическим методом решения этой задачи является использование кода на серверной стороне — команд, которые вы можете добавлять в ваши HTML страницы, «подключая» одну страницу в другую. Действительно, Django предоставляет поддержку этого метода с помощью вышеописанного тега {% include %}. Но более предпочтительным методом решения такой задачи с помощью Django является использование элегантной стратегии под названием наследование шаблонов.

В сущности, наследование шаблонов позволяет создать основной «скелетный» шаблон, который содержит все общие части вашего сайта и определить «блоки», которые могут быть заменены шаблонами-наследниками.

Давайте рассмотрим такой пример, создав более сложный шаблон для представления current_datetime. Отредактируем его:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">

<html lang="en">

<head>

<title>The current time</title>

</head>

<body>

<h1>My helpful timestamp site</h1>

<p>It is now {{ current_date }}.</p>


<hr>

<p>Thanks for visiting my site.</p>

</body>

</html>


Выглядит неплохо, но что случится, когда нам понадобится создать другое представление, скажем, hours_aheadиз главы «Представления и привязки URL». Если мы снова желаем получить приятный, правильный, полный HTML шаблон, нам потребуется создать нечто такое:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">

<html lang="en">

<head>

<title>Future time</title>

</head>

<body>

<h1>My helpful timestamp site</h1>

<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>


<hr>

<p>Thanks for visiting my site.</p>

</body>

</html>


Очевидно, что мы просто скопировали большую часть HTML. Представьте, что у нас более однородный сайт, включая навигационную панель, несколько стилей, возможно, немного JavaScript — нам потребуется использовать повторяющийся HTML в каждом шаблоне.

Решение этой проблемы с помощью подключения шаблонов на серверной стороне — выделение общих кусков в обоих шаблонах и сохранение их в отдельных шаблонах, которые затем включаются в каждый шаблон. Возможно, вы сохранили верхнюю часть шаблона в файле header.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">

<html lang="en">

<head>


И, возможно, вы сохранили нижнюю часть в файле footer.html:

<hr>

<p>Thanks for visiting my site.</p>

</body>

</html>


С помощью стратегии использования включений шаблонов, работать с заголовками и окончаниями страниц легко. Но подход неряшлив. В данном примере, у обеих страниц есть тег <title> — <h1>My helpful timestamp</h1> — но мы не можем поместить его в header.html, т.к. содержимое тегов различно. Если мы включим тег <h1> в заголовок, нам потребуется включить и <title>, что не позволит нам настраивать его содержимое для каждой страницы. Видите, куда это нас ведёт?

Система наследования шаблонов Django решает такие проблемы. Вы можете рассматривать её как версию с «вынесением различий» шаблонов на серверной стороне. Вместо определения общих частей шаблона, вы определяете различающиеся части.

Первым шагом является определение базового шаблона — основы вашей страницы, которую позже будут заполнять дочерние шаблоны. Ниже представлен базовый шаблон для нашего текущего примера:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">

<html lang="en">

<head>

<title>{% block title %}{% endblock %}</title>

</head>

<body>

<h1>My helpful timestamp site</h1>

{% block content %}{% endblock %}

{% block footer %}

<hr>

<p>Thanks for visiting my site.</p>

{% endblock %}

</body>

</html>


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

Здесь мы используем тег, который раньше не определяли: {% block %}. Всё, что такие теги делают — указывают шаблонной системе, что дочерние шаблоны могут переопределять эту часть основного шаблона.

Имея основной шаблон, мы можем внести изменения в существующий current_datetime.html, чтобы использовать его:

{% extends "base.html" %}


{% block title %}The current time{% endblock %}


{% block content %}

<p>It is now {{ current_date }}.</p>

{% endblock %}


Теперь, давайте создадим шаблон для представления hours_ahead из главы «Представления и привязки URL». (Если вы читаете, изменяя код, мы оставим на вас изменение кода hours_ahead для использования шаблонной системы.) Вот как он должен выглядеть:

{% extends "base.html" %}


{% block title %}Future time{% endblock %}


{% block content %}

<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>

{% endblock %}


Разве не прекрасно? Каждый шаблон содержит только уникальный код. Нет никакой избыточности. Если вам потребуется внести глобальные изменения в сайт, просто измените содержимое шаблона base.html и все остальные шаблоны немедленно отразят ваши изменения.

Вот так это работает. При загрузке шаблона current_datetime.html, шаблонная система видит тег {% extends %}, что означает, что перед ней дочерний шаблон. Система немедленно загружает базовый шаблон, в данном случае, base.html.

После этого, шаблонная система находит три тега {% block %} в base.html и заменяет эти блоки содержимым дочернего шаблона. Таким образом, заголовок, который мы определили в {% block title %} дочернего шаблона, будет использован вместо блока {% block title %} базового шаблона, а текст, определённый в {% block content %} — вместо блока {% block content %}.

Следует отметить, что раз дочерний шаблон не определяет блок footer, шаблонная система вместо этого использует значение из базового шаблона. Содержимое внутри тега {% block %} в основном шаблоне всегда используется в качестве запасного.

Наследование никак не влияет на работу контекста. Другими словами, любой шаблон в дереве наследования будет иметь доступ к каждому элементу контекста.

Вы можете использовать столько уровней наследования, сколько необходимо. Одним из общих способов использования наследования является следующий трёх-уровневый подход:

  1. Создать шаблон base.html, который содержит основную информацию о дизайне сайта. Эта часть изменяется очень редко, если вообще изменяется.
  2. Создать шаблон base_SECTION.html для каждого «раздела» вашего сайта (т.е. base_photos.html и base_forum.html). Эти шаблоны расширяют base.html и включают стили и дизайн для конкретного раздела.
  3. Создать индивидуальные шаблоны для каждого типа страниц, таких как страница форума или фотогалереи. Эти шаблоны расширяют определённые разделы шаблона.

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

Ниже приведены некоторые советы для работы с наследованием шаблонов:

  • Если вы используете {% extends %} в шаблоне, он должен быть первым тегом в этом шаблоне. В противном случае, наследование шаблонов работать не будет.
  • В общем случае, чем больше тегов {% block %} в основном шаблоне, тем лучше. Запомните, дочерние шаблоны не обязаны определять все блоки основного шаблона. Так что вы можете указать разумные значения по умолчанию в ряде блоков, а затем определить в дочернем шаблоне только те, которые надо изменить. Лучше иметь больше обработчиков.
  • Если вы заметили, что повторяете код в ряде шаблонов, возможно вам надо перенести этот код в {% block %}в основном шаблоне.
  • Если вам надо получить содержимое блока из основного шаблона, переменная {{ block.super }} поможет с этим. Это полезно, если вам потребуется лишь добавить данные в блок, вместо его полной замены.
  • Вы не можете определять множество тегов {% block %} с одинаковым именем в одном шаблоне. Это ограничение существует по причине того, что эти теги работают в «обоих» направлениях. То есть, этот тег не просто предоставляет место для заполнения данными, он также определяет содержимое, которое заполняет место в основном шаблоне. Если бы было два одинаково названных тега {% block %} в шаблоне, то основной шаблон бы не знал, какое содержимое блока использовать.
  • Шаблон, имя которого вы передаёте в {% extends %} загружается тем же способом, что и при использовании get_template(). То есть, имя шаблона добавляется к содержимому параметра TEMPLATE_DIRS.
  • В большинстве случаев, аргументом для тега {% extends %} будет строка. Но может быть и переменная, если вы не знаете имя основного шаблона до запуска приложения. Это позволяет вам реализовывать динамические вещи.
 
MyTetra Share v.0.65
Яндекс индекс цитирования