Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Django_-_podrobnoe_rukovodstvo

.pdf
Скачиваний:
308
Добавлен:
01.03.2016
Размер:
4.88 Mб
Скачать

70

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

Поиск имени может быть и многоуровневым. Например, конструкция {{ person.name.upper }} транслируется в последовательность из двух шагов: сначала производится обращение к словарю (person[‘name’]), а затем – вызов метода (upper()):

>>>from django.template import Template, Context

>>>person = {‘name’: ‘Sally’, ‘age’: ‘43’}

>>>t = Template(‘{{ person.name.upper }} is {{ person.age }} years old.’)

>>>c = Context({‘person’: person})

>>>t.render(c)

u’SALLY is 43 years old.’

Вызовы методов

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

Если во время вызова метода возникнет исключение, то оно распространяется вверх по стеку, если в объекте-исключении нет атрибута silent_variable_failure со значением True. Если же такой атрибут имеется, то при отображении переменная заменяется пустой строкой, как

вследующем примере:

>>>t = Template(“Меня зовут {{ person.first_name }}.”)

>>>class PersonClass3:

...

def first_name(self):

...

raise AssertionError, “foo”

>>>p = PersonClass3()

>>>t.render(Context({“person”: p})) Traceback (most recent call last):

...

AssertionError: foo

>>>class SilentAssertionError(AssertionError):

... silent_variable_failure = True

>>>class PersonClass4:

...

def first_name(self):

...

raise SilentAssertionError

>>>p = PersonClass4()

>>>t.render(Context({“person”: p})) u’Меня зовут .’

•• Вызов метода возможен, только если у метода нет обязательных аргументов. В противном случае система­ начнет проверять следующий по порядку вид доступа (поиск элемента списка по индексу).

•• Очевидно, что у некоторых методов есть побочные действия, и было бы глупо и, быть может, даже небезопасно разрешать системе­ шаб­ лонов обращаться к ним.

Пусть, например, в классе BankAccount имеется метод delete(). Если в шаблоне­ встречается конструкция {{ account.delete }}, где account –

Использование системы­ шаблонов­

71

объект класса BankAccount, то при отображении такого шаблона­ объект будет удален!

Чтобы предотвратить такое развитие событий, задайте для метода атрибут alters_data:

def delete(self):

# Удаление счета delete.alters_data = True

•• Система шаблонов­ не будет вызывать метод, помеченный таким образом. В приведенном выше примере, если в шаблоне­ встретится конструкция {{ account.delete }} и для метода delete() будет задан атрибут alters_data=True, то метод delete() не будет вызван при отображении. Он просто будет проигнорирован.

Как обрабатываются переменные, отсутствующие в контексте

По умолчанию, если переменная не определена в контексте, в процессе отображения система­ шаблонов­ выведет вместо нее пустую строку. Рассмотрим такой пример:

>>>from django.template import Template, Context

>>>t = Template(‘Вас зовут {{ name }}.’)

>>>t.render(Context())

u’Вас зовут .’

>>>t.render(Context({‘var’: ‘hello’})) u’Вас зовут .’

>>>t.render(Context({‘NAME’: ‘hello’})) u’Вас зовут .’

>>>t.render(Context({‘Name’: ‘hello’})) u’Вас зовут .’

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

Модификация контекстных объектов

В большинстве случаев при создании объектов Context конструктору передается заполненный словарь. Но разрешается добавлять и удалять элементы в объект Context и после его создания, для чего применяется стандартный синтаксис Python:

>>>from django.template import Context

>>>c = Context({“foo”: “bar”})

>>>c[‘foo’]

‘bar’

72

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

>>>del c[‘foo’]

>>>c[‘foo’]

Traceback (most recent call last):

...

KeyError: ‘foo’

>>>c[‘newvariable’] = ‘hello’

>>>c[‘newvariable’]

‘hello’

Простые шаблонные­ теги и фильтры

Мы уже отмечали, что в систему­ шаблонов­ уже встроен ряд тегов и фильтров. В следующих разделах мы приведем обзор наиболее употребительных.

Теги

В следующих разделах описаны часто используемые теги Django.

if/else

Тег {% if %} вычисляет переменную, и если она равна True (то есть существует, не пуста и не равна булевскому значению False), то система­ выводит все, что находится между тегами {% if %} и {% endif %}, как в примере ниже:

{% if today_is_weekend %}

<p>Вот и выходной настал!</p> {% endif %}

«Истинность» в языке Python

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

•• Пустой список ([])

•• Пустой кортеж (())

•• Пустой словарь ({})

•• Пустая строка (‘’)

•• Нуль (0)

•• Специальный объект None

•• Объект False (по очевидным причинам)

•• Пользовательские объекты, для которых определено поведение в булевском контексте. (Эта тема не для начинающих.)

Все остальное принимает значение True.

Простые шаблонные­ теги и фильтры

73

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

{% if today_is_weekend %}

<p>Вот и выходной настал!</p> {% else %}

<p>Пора снова на работу.</p> {% endif %}

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

{% if athlete_list and coach_list %} Есть и спортсмены, и тренеры.

{% endif %}

{% if not athlete_list %} Спортсменов нет.

{% endif %}

{% if athlete_list or coach_list %} Есть спортсмены или тренеры.

{% endif %}

{% if not athlete_list or coach_list %} Нет спортсменов или есть тренеры.

{% endif %}

{% if athlete_list and not coach_list %} Есть спортсмены и ни одного тренера.

{% endif %}

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

{% if athlete_list and coach_list or cheerleader_list %}

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

{% if athlete_list %}

{% if coach_list or cheerleader_list %}

Есть спортсмены и тренеры или группа поддержки! {% endif %}

{% endif %}

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

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

74

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

Тега {% elif %} не существует. Для достижения эквивалентного результата используйте вложенные теги {% if %}:

{% if athlete_list %}

<p>Список спортсменов: {{ athlete_list }}.</p> {% else %}

<p>Нет никаких спортсменов.</p> {% if coach_list %}

<p>Список тренеров: {{ 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 %}

Обычно перед началом цикла­ принято проверять размер списка и, если список пуст, выводить какой-нибудь подходящий текст:

Простые шаблонные­ теги и фильтры

75

{% if athlete_list %}

{% for athlete in athlete_list %} <p>{{ athlete.name }}</p>

{% endfor %} {% else %}

<p>Спортсменов нет. Только программисты.</p> {% endif %}

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

{% for athlete in athlete_list %} <p>{{ athlete.name }}</p>

{% empty %}

<p>Спортсменов нет. Только программисты.</p> {% endfor %}

Не существует способа выйти из цикла­ до его естественного завершения. Если нечто подобное необходимо, измените переменную последовательности, обход которой осуществляется в цикле,­ так чтобы она содержала только нужные значения. Точно так же не существует аналога инструкции «continue», который позволял бы немедленно перейти в начало цикла­. (Ниже, в разделе «Идеология и ограничения», объясняется, почему принято такое проектное решение.)

Внутри цикла­ {% for %} имеется доступ к шаблонной­ переменной с именем forloop. У нее есть несколько атрибутов, позволяющих получить сведения о текущем состоянии цикла:­

•• forloop.counter всегда показывает, сколько итераций цикла­ уже выполнено. Отсчет начинается с единицы, поэтому на первой итерации forloop.counter равен 1. Пример:

{% for item in todo_list %}

<p>{{ forloop.counter }}: {{ item }}</p> {% endfor %}

•• forloop.counter0 аналогичен forloop.counter с тем отличием, что отсчет начинается с нуля. На первой итерации цикла­ значение этого атрибута равно 0.

•• forloop.revcounter всегда показывает, сколько итераций осталось выполнить. На первой итерации цикла­ значение атрибута forloop. revcounter равно количеству элементов в перебираемом списке. На последней итерации этот счетчик равен 1.

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

76

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

•• forloop.first – булевское значение, равное True на первой итерации цикла­. Этот атрибут удобен для обработки граничных случаев:

{% for object in objects %}

{% if forloop.first %}<li class=”first”>{% else %}<li>{% endif %} {{ object }}

</li> {% endfor %}

•• forloop.last – булевское значение, равное True на последней итерации цикла­. Часто применяется для вставки знаков разделителей между элементами списка ссылок:

{% for link in links %} {{ link }}

{% if not forloop.last %}

|

{% endif %}{% endfor %}

Этот код порождает примерно такой результат:

Link1 | Link2 | Link3 | Link4

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

Любимые места:

{% for p in places %} {{ p }}

{% if not forloop.last %}

,

{% endif %} {% endfor %}

•• forloop.parentloop – ссылка на объект forloop объемлющего цикла­ в случае, когда циклы­ вложены, например:

{% for country in countries %} <table>

{% for city in country.city_list %} <tr>

<td>Страна #{{ forloop.parentloop.counter }}</td> <td>Город #{{ forloop.counter }}</td>

<td>{{ city }}</td> </tr>

{% endfor %} </table>

{% endfor %}

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

Простые шаблонные­ теги и фильтры

77

Контекст и переменная forloop

Внутри блока {% for %} существующие переменные маскируются, чтобы избежать перезаписи магической переменной forloop. Django предоставляет доступ к замаскированному контексту через объект forloop.parentloop. Обычно это не вызывает никаких осложнений, но если в шаблон­ передана переменная с именем forloop (а мы настоятельно рекомендуем этого не делать, чтобы не вводить в заблуждение своих коллег), то внутри блока {% for %} она будет называться forloop.parentloop.

ifequal/ifnotequal

Систему шаблонов­ в Django сознательно не стали превращать в полноценный язык программирования, поэтому выполнять произвольные предложения языка Python она не может. (Дополнительные сведения по этому поводу см. в разделе «Идеология и ограничения».) Однако в шаблонах­ часто возникает необходимость сравнить два значения и вывести что-то, если они равны. Для этой цели Django предлагает тег

{% ifequal %}.

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

Вследующем примере сравниваются шаблонные­ переменные user

иcurrentuser:

{% ifequal user currentuser %} <h1>Добро пожаловать!</h1>

{% endifequal %}

В качестве аргументов могут выступать строковые литералы, заключенные в одиночные или двойные кавычки, поэтому следующий шаб­ лон допустим:

{% ifequal section ‘sitenews’ %} <h1>Новости сайта</h1>

{% endifequal %}

{% ifequal section “community” %} <h1>Сообщество</h1>

{% endifequal %}

Так же как и {% if %}, тег {% ifequal %} поддерживает необязательную ветвь {% else %}:

{% ifequal section ‘sitenews’ %} <h1>Новости сайта</h1>

{% else %}

78

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

<h1>Новостей нет</h1> {% endifequal %}

Аргументами тега {% ifequal %} могут быть только шаблонные­ переменные, строки, целые числа и числа с плавающей точкой. Ниже приведены примеры допустимого кода:

{% 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 могут быть комментарии. Комментарий обозначается тегом {# #}:

{# Это комментарий #}

При отображении шаблона­ комментарий не выводится.

Показанный выше синтаксис не допускает многострочных комментариев. Это ограничение повышает скорость синтаксического анализа шаблона­. В следующем примере выведенный текст будет выглядеть в точности так же, как сам шаблон­ (то есть тег комментария не воспринимается как комментарий):

Это {# это не комментарий #} тест.

Если вам понадобятся многострочные комментарии, используйте шаб­ лонный тег {% comment %}:

{% comment %} Это

многострочный комментарий. {% endcomment %}

Фильтры

Как было сказано выше, шаблонные­ фильтры дают простой способ изменить внешний вид переменной при отображении. В фильтрах используется символ конвейера, например:

Идеология и ограничения

79

{{name|lower }}

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

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

{{ my_list|first|upper }}

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

{{bio|truncatewords:”30” }}

Врезультате выводятся первые 30 слов из значения переменной bio.

Ниже описываются наиболее употребительные фильтры. Остальные описаны в приложении F.

•• addslashes: добавляет символ обратного слеша перед каждым из следующих символов: обратный слеш, одиночная кавычка, двойная кавычка. Это полезно, когда генерируемый текст предполагается включить в JavaScript-сценарий.

•• date: форматирует объект date или datetime в соответствии со строкой формата, переданной в качестве параметра, например:

{{ pub_date|date:”F j, Y” }}

Форматные строки описаны в приложении F.

•• length: возвращает длину значения. Для списка возвращает количество элементов в нем, для строки – количество символов. (Для хорошо знающих язык Python отметим, что этот фильтр применим к любому объекту, который умеет вычислять собственную длину, то есть к объектам, в которых определен метод __len__()).

Идеология и ограничения

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

Синтаксис шаблонов­ субъективен, пожалуй, в большей степени, чем любой другой компонент веб-приложений, и мнения программистов по этому поводу сильно разнятся. Об этом свидетельствует наличие десятков, если не сотен, открытых реализаций языков шаблонов­ только на Python. И надо полагать, что каждая из них была написана потому, что все существующие языки шаблонов­ автору не понравились. (Считается даже, что написание собственного языка шаблонов­ – обряд посвящения в программисты на Python! Если вы еще этого не делали, попробуйте, это хорошее упражнение.)

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]