Теги шаблонов. Теги if и for

Курс по Django: https://stepik.org/a/183363

Архив проекта: 12_sitewomen.zip

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

https://docs.djangoproject.com/en/4.2/ref/templates/builtins/

Сразу обращает на себя запись тегов в виде последовательности символов:

{% <название тега> [параметры] %}

И чтобы было понятно, что из себя представляют шаблонные теги и для чего они нужны, рассмотрим на этом занятии два очень распространенных тега if и for. Начнем с тега for.

Давайте предположим, что у нас имеется список из данных по известным женщинам, например, такой:

data_db = [
    {'id': 1, 'title': 'Анджелина Джоли', 'content': 'Биография Анджелины Джоли', 'is_published': True},
    {'id': 2, 'title': 'Марго Робби', 'content': 'Биография Марго Робби', 'is_published': False},
    {'id': 3, 'title': 'Джулия Робертс', 'content': 'Биография Джулия Робертс', 'is_published': True},
]

Здесь каждый элемент представляет собой словарь из четырех ключей: id, title, content и is_published. Их назначение вполне очевидно. Последний ключ is_published означает опубликована статья или нет (True – опубликована; False – не опубликована).

В функции представления index сформируем общие данные и передадим их в шаблон index.html:

def index(request):
    data = {
        'title': 'Главная страница',
        'menu': menu,
        'posts': data_db,
    }
 
    return render(request, 'women/index.html', context=data)

Как видите, в шаблоне будет доступна коллекция posts из набора публикуемых статей. Наша задача отобразить этот список. В самом простом варианте это можно сделать следующим образом (в шаблоне index.html):

<!DOCTYPE html>
<html>
<head>
         <title>{{ title }}</title>
</head>
<body>
<p >{{ menu|join:" | " }}</p>
<h1>{{ title }}</h1>
 
<ul>
         {% for p in posts %}
         <li>
                   <h2>{{ p.title }}</h2>
                   <p >{{ p.content }}</p>
                   <hr>
         </li>
         {% endfor %}
</ul>
 
</body>
</html>

Смотрите, здесь внутри HTML-тега ul записан тег for шаблонизатора Django. Не путайте эти две вещи: есть теги разметки HTML-документа, а есть теги шаблонизатора. Теги шаблонизатора отрабатывают на стороне сервера и служат для формирования общего вида HTML-документа, который, затем, возвращается пользователю. А в браузере клиента обрабатываются уже HTML-теги, в частности, для форматирования выводимой информации на экране устройства. Так вот, тег for – это тег шаблонизатора Django, который работает по аналогии с оператором цикла for языка Python и в нашем примере перебирает переданную коллекцию posts. Конец тега-цикла for обязательно должно быть отмечено тегом endfor. Все, что попадает между этими тегами, образует тело цикла и повторяется на каждой итерации. То есть, на каждой итерации в HTML-документ будет добавляться тег li с соответствующим содержимым: заголовком h2, абзацем p с текстом статьи и разделительной линией (тег hr).

Как видите, бэк-разработчик тоже должен немного знать правила HTML-разметки, чтобы грамотно формировать шаблоны на стороне сервера. Если этих знаний у вас недостаточно, то смотрите краткое введение в плейлисте по HTML:

https://www.youtube.com/playlist?list=PLA0M1Bcd0w8wRiyGX_9y-fUiBPi1vqaTb

После запуска тестового веб-сервера и перехода на главную страницу увидим такую HTML-страницу:

Но у нас здесь, во-первых, выводится информация по Марго Робби, хотя для нее ключ is_published установлен в False и, во-вторых, последняя горизонтальная черта явно лишняя. Давайте поправим эти моменты. Вначале уберем последнюю горизонтальную черту. Для этого воспользуемся еще одним шаблонным тегом if, который позволяет проверять условия и работает подобно оператору if языка Python. Тег hr заключим в этот условный тег со следующей проверкой условия:

<ul>
         {% for p in posts %}
         <li>
                   <h2>{{p.title}}</h2>
                   <p >{{p.content}}</p>
                   {% if not forloop.last %}
                   <hr>
                   {% endif %}
         </li>
         {% endfor %}
</ul>

Смотрите, мы внутри тега for можем использовать специальную переменную forloop, которая содержит некоторую вспомогательную информацию:

https://docs.djangoproject.com/en/4.2/ref/templates/builtins/#for

В частности, переменную last, которая принимает значение True на последней итерации цикла. Поэтому условие not forloop.last истинно, пока мы не дошли до последней итерации. Соответственно, тег hr добавляется во все пункты li, кроме последнего. Обратите внимание, что в конце тега if обязательно нужно прописать тег endif. Все, что попадает в промежуток между if и endif образуют фрагмент HTML-документа, который включается или не включается в зависимости от истинности условия.

После обновления главной страницы увидим, что последняя горизонтальная черта пропала, как мы этого и хотели. Давайте теперь по аналогии будем отображать только те статьи, для которых значение поля is_published равно True. Сделать это можно следующим образом:

<ul>
         {% for p in posts %}
         {% if p.is_published %}
         <li>
                   <h2>{{p.title}}</h2>
                   <p >{{p.content}}</p>
                   {% if not forloop.last %}
                   <hr>
                   {% endif %}
         </li>
         {% endif %}
         {% endfor %}
</ul>

Так как между шаблонными тегами if и endif заключен фрагмент с HTML-тегом li, то при ложном is_published соответствующая статья добавлена в HTML-документ не будет. И мы это увидим при обновлении главной страницы. На ней останется только две статьи.

Как видите, шаблонные теги for и if применять достаточно просто, и работают они аналогично операторам for и if языка Python. Например, в условиях также можно прописывать составные условия с применением операторов not, and и or. Добавлять блоки elif и else при необходимости. И, я думаю, с этим ни у кого из вас не возникнет никаких проблем, все достаточно очевидно.

На следующем занятии мы продолжим эту тему и познакомимся со следующим важным шаблонным тегом url.

Курс по Django: https://stepik.org/a/183363

Видео по теме