Разбиваем шаблоны в Django: include, block, extends.

Обычно шаблоны не пишут целиком в одном файле: их разделяют на части и сохраняют в отдельных файлах.При подготовке ответа возвращаемая HTML-страница монтируется из этих фрагментов, как из конструктора Lego, и в собранном виде отправляется клиенту.Для такой практики есть несколько веских причин.

  • Как правило, страницы проекта содержат повторяющиеся фрагменты: шапка сайта, подвал, блок навигации. Карточки товаров в интернет-магазине или анонсы статей на информационном ресурсе тоже свёрстаны одинаково. Эти элементы в одинаковом виде присутствуют на многих страницах. Код каждого такого элемента сохраняют в отдельный файл, а при рендеринге встраивают их в общий шаблон. В этом тоже реализация принципа DRY: если, например, потребуется изменить шапку сайта, изменения вносятся в один файл. В ином случае пришлось бы редактировать десятки шаблонов, исправляя шапку в каждом из них.
  • Шаблон для нового типа страницы можно подготовить за считанные минуты, собрав его из готовых фрагментов, как из конструктора.

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

Тег {% include %}: собираем шаблон из фрагментов

Повторяющиеся части шаблонов можно вынести в отдельные файлы и по необходимости подключать к любой странице. Для подключения применяют тег {% include 'адрес_подключаемого шаблона' %}. Подключаемые шаблоны обычно хранят в специальной папке includes/ в директории с шаблонами приложения, если они применяются только в шаблонах приложения. Если же подключаемые шаблоны применяются в масштабе всего проекта — их сохраняют в папке includes/ в корневой директории шаблонов.

anfisa
├── ...
├── templates
|    ├── ice_cream 
│    |   ├── includes <-- Папка для повторяющихся частей шаблонов приложения
│    |   ├── ice_cream_detail.html 
│    |   ├── ice_cream_list.html   
│    |   └── index.html            
│    └── includes <-- Папка для повторяющихся частей шаблонов проекта
│        ├── header.html
│        └── footer.html
└──  ... 

Для включения кода из одного файла в другой применяют тег шаблонизатора {% include %}. Аргументом для этого тега указывается относительный адрес шаблона, код которого надо включить в файл: {% include 'адрес_файла.html' %}. Если повторяющиеся части — код шапки сайта и подвала — вынести в отдельные файлы, код главной страницы может выглядеть примерно так:

<!-- templates/ice_cream/index.html -->
<!DOCTYPE html> 
<html lang="ru">          
  <head>       
  </head>
  <body>       
    <header>
      <!-- Это тег шаблонизатора include, сюда будет включён код
      из файла includes/header.html -->
      {% include 'includes/header.html' %}
    </header>
    <main>
      Информация на главной странице
    </main>
    <footer>
      {% include 'includes/footer.html' %} 
    </footer>
  </body>
</html> 

Другие страницы будут выглядеть аналогично:

<!-- templates/ice_cream/ice_cream_list.html --> 
<!DOCTYPE html> 
<html lang="ru">          
  <head>       
  </head>
  <body>       
    <header>
      {% include 'includes/header.html' %}     
    </header>
    <main>
      Список мороженого быть тут должен
    </main>
    <footer>
      {% include 'includes/footer.html' %} 
    </footer>
  </body>
</html> 

В остальных шаблонах указывается, что они являются дочерними для базового шаблона (или «расширяют» его: англ. extend — «расширять»):

<!-- templates/ice_cream/index.html --> 
{% extends 'base.html' %} 
<!-- templates/ice_cream/ice_cream_list.html --> 
{% extends 'base.html' %} 

Когда view-функция Django вызывает какой-то шаблон, например…

...
def index(request):
    template = 'ice_cream/index.html'
    return render(request, template) 

…а в вызванном шаблоне видит тег {% extends 'base.html' %}

<!-- templates/ice_cream/index.html --> 
{% extends 'base.html' %} 

…будет вызван шаблон base.html. Если в базовом шаблоне есть теги {% include %} — в них выполнятся все инструкции.Но самое важное: дочерние шаблоны могут менять информацию в блоках, описанных в родительском.

Комментарии

Django-шаблоны поддерживают комментарии — строки, которые игнорируются при интерпретации кода.Комментарии могут быть трёх типов:

  1. Однострочные комментарии: записываются между символами {# и #},
  2. Многострочные комментарии пишут между конструкциями {% comment %} и {% endcomment %}.
  3. Стандартные HTML- комментарии: их тоже можно применять, если комментируемая строка не содержит переменных шаблона; записывается между конструкциями <!-- и -->.
{% comment "Опциональный текст, поясняющий смысл закомментированного" %}
  1 вариант: многострочный.
  <p>Этот кусок шаблона временно отключён {{ create_date|date:"c" }}</p>
  <p>Уходя, гасите свет.</p>
{% endcomment %}

{# 2 вариант: однострочный; можно комментировать переменные {{ varaible }} #}
{# А можно применять для заметок #}

<!-- 3 вариант: только для HTML кода. Не вставляйте в него перемнные --> 

Тег {% block %}: изменяем содержимое базового шаблона из дочернего

Пример шаблона base.html с блоком content:

<!-- templates/base.html -->
<!DOCTYPE html> 
<html lang="ru">          
  <head>       
  </head>
  <body>       
    <header>
      {% include 'includes/header.html' %}
    </header>
    <main>
      {% block content %}
        Контент не подвезли :(
      {% endblock %}
    </main>
    <footer>
      {% include 'includes/footer.html' %} 
    </footer>
  </body>
</html> 

Теперь из любого дочернего шаблона можно изменить содержимое блока content.На главной:

<!-- templates/ice_cream/index.html --> 
{% extends 'base.html' %}
{% block content %}
  Это главная страница проекта «Анфиса для друзей»!
{% endblock %} 

Теперь, если из view-функции будет вызван шаблон ice_cream/index.html, события будут развиваться так:

  1. Вызывается шаблон ice_cream/index.html.
  2. В файле index.html шаблонизатор видит тег {% extends 'base.html' %} и вызывает шаблон base.html.
  3. В шаблоне base.html Django обнаруживает теги include и встраивает код из подключаемых файлов header.html и footer.html.
  4. В изначально вызванном файле index.html Django видит тег {% block content %} с неким содержимым, ищет одноимённый блок в базовом шаблоне и, если находит, встраивает содержимое блока из дочернего файла в базовый.

При вызове страницы со списком сортов мороженого произойдёт всё то же самое, но содержимое блока {% block content %} может быть иным — соответственно, иным будет и содержимое веб-страницы, которая вернётся пользователю:

<!-- templates/ice_cream/ice_cream_list.html --> 
{% extends 'base.html' %}
{% block content %}
  Список мороженого быть тут должен
{% endblock %} 

Дочерние шаблоны получаются простыми и легкоизменяемыми.Если в тег block ничего не передано или он отсутствует в дочернем шаблоне — на веб-страницу будет выведено значение, которое предустановлено в базовом шаблоне. Сейчас в коде базового шаблона в блоке content предустановлен текст Контент не подвезли :(.Но предустановленного значения может и не быть, оно необязательно.

Структура

Поскольку блоки в директории /includes и базовый шаблон base.html относятся не к какому-то определённому приложению, а ко всему проекту в общем, то будет удобно хранить их не в папке с шаблонами приложения, а отдельно, прямо в директории /templates. И структура шаблонов проекта «Анфиса для друзей» в такой логике будет выглядеть так:

anfisa
├── anfisa/     #  Главная папка проекта
├── ice_cream/  #  Папка приложения
├── templates   <-- Директория для шаблонов
│    ├── ice_cream       <-- Директория для шаблонов приложения ice_cream
│    │   ├── ice_cream_detail.html # Шаблон страницы для отдельного мороженого
│    │   ├── ice_cream_list.html   # Шаблон страницы со списком мороженого
│    │   └── index.html            # Шаблон главной страницы
│    ├── includes          <-- Директория с подключаемыми шаблонами
│    │   ├── header.html   # Верхняя часть страниц
│    │   └── footer.html   # Нижняя часть страниц
│    └──  base.html        # Базовый шаблон       
└──  manage.py 




Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: