Found misprint?

Select it with the mouse and hit Enter

Ctrl-Enter
Обработано:
86 1 199 25
The full repository of DjangoBook translation you can get on GitHub.
We appreciate your patches!
Мы рады получить ваши вопросы, комментарии или предложения!
(Open in new tab)
Количество пользователей: 1135

Документация Django на русском

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

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

До этого момента наши примеры шаблонов содержали крошечные фрагменты 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 %} будет строка. Но может быть и переменная, если вы не знаете имя основного шаблона до запуска приложения. Это позволяет вам реализовывать динамические вещи.

djoa
djoa 2 недели, 4 дня прошло
Ответить | Ссылка

ответить Nule
Жаль, что не раскрыто, как работает {{ block.super }}

{{ block.super }} просто подставляет вместо себя дефолтовое значение блока, внутри которого находимся.

Пример для hours_ahead.html - добавляем в {{% block footer %}} строку "Hello!" после дефолтового контента, заданного в base.html:
{% extends "base.html" %}

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

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

{% block footer %}
{{ block.super }}
Hello!
{% endblock %}

Nule
Nule 2 недели, 6 дней прошло
Ответить | Ссылка

Жаль, что не раскрыто, как работает {{ block.super }}

alerion
alerion 6 месяцев прошло
Ответить | Ссылка

ответить Ironman
Доброго всем времени суток! Пробовал переделать функцию hours_ahead в файле views.py для использования в шаблонной системе, приведенной в данном примере, положительного результата так и не получил. Подскажите как переделать функцию hours_ahead, чтобы она могла быть использована с шаблонной системой. На данный момент функция выглядит у меня так:

def hours_ahead(request, offset):
try:
offset = int(offset)
except ValueError:
raise Http404()
dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
return render_to_response('hours_ahead.html', {'hours_offset': offset, 'next_time': dt})

Буду очень благодарен за помошь.

p.s. Пока еще не разобрался до конца со всем, но концепции заложенные в django мне очень нравится. Шаблонная система в django великолепна!

Вопросы задавайте на форуме.

Ironman
Ironman 6 месяцев, 1 неделя прошло
Ответить | Ссылка

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

def hours_ahead(request, offset):
try:
offset = int(offset)
except ValueError:
raise Http404()
dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
return render_to_response('hours_ahead.html', {'hours_offset': offset, 'next_time': dt})

Буду очень благодарен за помошь.

p.s. Пока еще не разобрался до конца со всем, но концепции заложенные в django мне очень нравится. Шаблонная система в django великолепна!

alerion
alerion 1 год, 4 месяца прошло
Ответить | Ссылка

ответить zheka-77
{% extends "base.html" %}
{% block contents %}
{% for post in posts %}
<h2>...</h2>
<p>...</p>
<p>...</p>
{% endfor %}
{% endblock %}

при наследование базового шаблона добавляется пустая строка,и все содержимое смещается на одну строку на листе
ПОЧЕМУ?

Вопросы задавайте на форуме.

zheka-77
zheka-77 1 год, 4 месяца прошло
Ответить | Ссылка

{% extends "base.html" %}
{% block contents %}
{% for post in posts %}
<h2>...</h2>
<p>...</p>
<p>...</p>
{% endfor %}
{% endblock %}

при наследование базового шаблона добавляется пустая строка,и все содержимое смещается на одну строку на листе
ПОЧЕМУ?

sky.fion
sky.fion 1 год, 6 месяцев прошло
Ответить | Ссылка

это прекрасно)

alerion
alerion 1 год, 6 месяцев прошло
Ответить | Ссылка

ответить stranger61
{% extends "base.html" %}

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

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

Разве не прекрасно?
--------------------------

1. {% extends "base.html" %} - жесткая связь с щаблоном base.html - не очень прекрасно.

2. Доля html-кода состявляет 4%. Верстальщики с ума сойдут.

З.Ы. Все вышенаписанное - мое субъективное мнение.

А как вы предлагаете? Это простой пример. В реальном приложении в block content будет столько HTML, сколько вам нужно.

> жесткая связь с щаблоном base.html

Приведите пример не жесткой. И что тут жеткого? То, что вам нужно поменять одну строку для изменения базового шаблона? Это сделано для удобства верстальщика. Что бы он не правил шапку и футер в 20+ шаблонах.

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

stranger61
stranger61 1 год, 7 месяцев прошло
Ответить | Ссылка

{% extends "base.html" %}

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

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

Разве не прекрасно?
--------------------------

1. {% extends "base.html" %} - жесткая связь с щаблоном base.html - не очень прекрасно.

2. Доля html-кода состявляет 4%. Верстальщики с ума сойдут.

З.Ы. Все вышенаписанное - мое субъективное мнение.