Django Book: основные теги и фильтры шаблона

Автор: | 02/14/2015
 

django_logo_2Как мы уже упоминали в предыдущей части — в систему шаблонов включены теги и шаблоны. В этой части мы кратко рассмотрим наиболее используемые из них.

Теги (tags)

if/else

Тег {% if %} проверяет значение переменной, и если оно True (т.е. — она не пустая, и её булево значение не false) — система отобразит всё, что указано между {% if %} и {% endif %}, например:

{% if today_is_weekend %}
    <p>Welcome to the weekend!</p>
{% endif %}

Тег {% else %} не обязателен:

{% if today_is_weekend %}
    <p>Welcome to the weekend!</p>
{% else %}
    <p>Get back to work.</p>
{% endif %}

Проверка значений в Python

В Python и в системе шаблонов Django следующие объекты будут иметь значение False:

  • пустой список ([]);
  • пустой кортеж (());
  • пустой словарь ({});
  • пустая строка ('');
  • ноль (0);
  • специальный объект None;
  • объект False (это очевидно);
  • другие объекты, которые имеют собственное логическое поведение;

Всё остальное будет иметь значение True

Тег {% if %} может принимать операторы and, or или not для проверки нескольких переменных. Например:

{% if athlete_list and coach_list %}
    Both athletes and coaches are available.
{% endif %}

{% if not athlete_list %}
    There are no athletes.
{% endif %}

{% if athlete_list or coach_list %}
    There are some athletes or some coaches.
{% endif %}

{% if not athlete_list or coach_list %}
    There are no athletes or there are some coaches.
{% endif %}

{% if athlete_list and not coach_list %}
    There are some athletes and absolutely no coaches.
{% endif %}

С тегом {% if %} нельзя одновременно использовать операторы and и or, так как это сделает результат двусмысленным. Следующий пример будет некорректным:

{% if athlete_list and coach_list or cheerleader_list %}

Использование скобок для контроля над порядком операций недопустимо. Если вы всё же решили, что вам необходимо использование скобок — выполните логическую выборку вне шаблона, и передайте результат как отдельную переменную. Либо — используйте вложенный тег {% if %}, например так:

{% if athlete_list %}
    {% if coach_list or cheerleader_list %}
        We have athletes, and either coaches or cheerleaders!
    {% endif %}
{% endif %}

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

{% if athlete_list or coach_list or parent_list or teacher_list %}

В Django нет тега {% elif %}, но вы можете использовать вложенные теги {% if %} для реализации задачи:

{% if athlete_list %}
    <p>Here are the athletes: {{ athlete_list }}.</p>
{% else %}
    <p>No athletes are available.</p>
    {% if coach_list %}
        <p>Here are the coaches: {{ coach_list }}.</p>
    {% endif %}
{% endif %}

Убедитесь, что все теги {% if %} закрыты {% endif %}. Иначе — Django вызовет исключение TemplateSyntaxError.

for

Тег {% for %} позволяет вам выполнять итерацию элементов в последовательности. Как и оператор for в Python, синтаксис его выглядит как for X in Y, где Y — это последовательность элементов, а X — имя переменной для использования в каждом цикле. Каждый раз при выполнении цикла — система шаблонов будет выполнять рендеринг всего, что заключено между {% for %} и {% endfor %}.

Например, вы можете использовать такой код для отображения списка спортсменов, заданных в списке athlete_list:

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>

Вы может добавить reversed , что бы выполнить итерацию в обратном порядке:

{% for athlete in athlete_list reversed %}
...
{% endfor %}

Допустимо использование вложенных циклов {% for %}:

{% for athlete in athlete_list %}
    <h1>{{ athlete.name }}</h1>
    <ul>
    {% for sport in athlete.sports_played %}
        <li>{{ sport }}</li>
    {% endfor %}
    </ul>
{% endfor %}

Распространённая практика — проверять размер списка перед выполнением итерации, и выводить какой-то другое сообщение, если он пуст:

{% if athlete_list %}
    {% for athlete in athlete_list %}
        <p>{{ athlete.name }}</p>
    {% endfor %}
{% else %}
    <p>There are no athletes. Only computer programmers.</p>
{% endif %}

Так как такая проверка используется очень часто, поэтому тег for поддерживает оператор {% empty %}, который позволяет определить — что отображать, если список пустой. Следующий пример будет работать так же, как и предыдущий

{% for athlete in athlete_list %}
    <p>{{ athlete.name }}</p>
{% empty %}
    <p>There are no athletes. Only computer programmers.</p>
{% endfor %}

В тегах Django нет аналога оператора break для выхода из цикла до его завершения. Если вы хотите выполнить подобное действие — измените саму переменную, участвующую в цикле так, что бы в ней были только те данные, которые должны быть в цикле (примечание: тут>>> есть примеры того, что имеется ввиду в этом параграфе). Аналогично — нет поддержки оператора continue, который должен возвращать выполнение цикла к его началу (смотрите следующий раздел «Философия и Ограничения» далее в этой главе).

Внутри каждого цикла {% for %}  у вас есть доступ к переменной шаблона forloop. Она содержит несколько атрибутов, которые могу предоставить вам информацию о процессе выполнения цикла:

  • forloop.counter содержит в себе количество выполненных итераций цикла. Его индекс начинается с 1, а не с 0, и при первом выполнении цикла forloop.counter будет равен 1. Например:

    {% for item in todo_list %}
        <p>{{ forloop.counter }}: {{ item }}</p>
    {% endfor %}
  • forloop.counter0 аналогичен с forloop.counter, но его отсчёт начинается с нуля, а не единицы.

  • forloop.revcounter содержит в себе количество оставшихся итераций. При первом выполнении цикла этот счётчик будет содержать в себе общее количество элементов в заданной циклу последовательности. При выполнении последней итерации — он будет равен 1.

  • forloop.revcounter0 аналогичен forloop.revcounter, с той разницей, что он заканчивается на 0, а не 1. При первом выполнении цикла — его значение будет равно общему количеству элементов -1, а при последнем — нулю.

  • forloop.first — логическое (булево) значение, содержит True при первом выполнении цикла. Удобен для особых случаев, например:

    {% for object in objects %}
        {% if forloop.first %}<li class="first">{% else %}<li>{% endif %}
        {{ object }}
        </li>
    {% endfor %}
  • forloop.last — аналогичен forloop.first, но будет True при последнем выполнении цикла. Часто используется для добавления | между элементами списка ссылок:

    {% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}

    Результат будет выглядеть так:

    Link1 | Link2 | Link3 | Link4
    

    Другой пример использования — добавление запятой между словами в списке:

    Favorite places:
    {% for p in places %}{{ p }}{% if not forloop.last %}, {% endif %}{% endfor %}
  • forloop.parentloop — ссылка на родительский цикл в случаях с вложенными циклами, например:

    {% for country in countries %}
        <table>
        {% for city in country.city_list %}
            <tr>
            <td>Country #{{ forloop.parentloop.counter }}</td>
            <td>City #{{ forloop.counter }}</td>
            <td>{{ city }}</td>
            </tr>
        {% endfor %}
        </table>
    {% endfor %}

Специальная переменная forloop допустима только в циклах. Как только парсер шаблона достигнет {% endfor %} — переменная forloop исчезнет.

Context и переменная forloop

Внутри блока {% for %} существующие переменные «сдвигаются», что бы избежать перезаписи значения специальной переменной forloop. Как правило, вам не стоит переживать на этот счёт, но если вы используете свою переменную forloop (хотя это не рекомендуется), она будет названа forloop.parentloop внутри всего блока {% for %}.

ifequal/ifnotequal

Система шаблонов Django разработана не как язык программирования, и в ней недопустимо использование обычных операторов Python. Однако, очень часто требуется сравнить две переменные и отобразить что-либо, если они не идентичны — для этого в Django используется тег {% ifequal %}.

Тег  {% ifequal %} сравнивает два значения, и отображает всё, что задано между  {% ifequal %} и {% endifequal %} если значения одинаковы.

В этом примере сравниваются две переменные шаблона — user и currentuser:

{% ifequal user currentuser %}
    <h1>Welcome!</h1>
{% endifequal %}

Аргументами можно использовать непосредственно строку, заключённую в одинарные или двойные кавычки:

{% ifequal section 'sitenews' %}
    <h1>Site News</h1>
{% endifequal %}

{% ifequal section "community" %}
    <h1>Community</h1>
{% endifequal %}

Как и в теге {% if %}, в {% ifequal %} можно использовать {% else %}:

{% ifequal section 'sitenews' %}
    <h1>Site News</h1>
{% else %}
    <h1>No News Here</h1>
{% endifequal %}

В качестве аргументов можно использовать только переменные, строки, целые и десятичные числа:

{% ifequal variable 1 %}
{% ifequal variable 1.23 %}
{% ifequal variable 'foo' %}
{% ifequal variable "foo" %}

Любые другие типы переменных, такие как словари, списки и логические типы — недопустимы. Вот неправильные примеры использования {% ifequal %}:

{% ifequal variable True %}
{% ifequal variable [1, 2, 3] %}
{% ifequal variable {'key': 'value'} %}

Если вам необходимо проверить что-либо истинно или ложно — используйте тег {% if %} вместо {% ifequal %}.

Комментарии

Как и в HTML или Python, система шаблонов Django поддерживает добавление комментариев в код. Что бы обозначить его — используйте тег {# #}:

{# This is a comment #}

Этот комментарий не будет отображён при рендеринге шаблона.

Комментарии с использованием {# #} могут быть только однострочными — такое ограничение ускоряет парсинг шаблона.

Если вы хотите использовать многострочный комментарий — используйте тег {% comment %}, например:

{% comment %}
This is a
multi-line comment.
{% endcomment %}

Фильтры

Как уже было сказано в этой главе ранее, фильтры шаблона  являются самым простым и удобным способом изменить значение переменной перед её отображением. Фильтры используют символ pipe |, например так:

{{ name|lower }}

Таким образом будет выведено значение переменной {{ name }} после применения фильтра lower, который переведёт текст в нижний регистр символов.

Фильтры могут быть объединены в цепочки и использованы вместе, таким образом вывод одного фильтра будет передан на обработку второму фильтру. В следующем примере первый элемент списка попадает под фильтр, а потом изменяется в заглавные символы:

{{ my_list|first|upper }}

Некоторые фильтры могут принимать аргументы. Аргументы фильтра указываются после двоеточия и в двойных кавычках:

{{ bio|truncatewords:"30" }}

Так будут выведены первые 30 символов переменной bio.

Вот несколько наиболее полезных фильтров:

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

  • date — форматирование объектов date или datetime в соответствии с заданными параметрами, например:

    {{ pub_date|date:"F j, Y" }}
  • length — возвращает длину значения переменной. Для списка — количество элементов, для строки — количество символов. Работает  с любым объектом, который поддерживает метод __len__().

Продолжение — Django Book: философия и ограничения.