Давайте рассмотрим шаблонную систему Django подробнее, вы сможете увидеть как она работает, но пока мы не будем интегрировать её с представлениями, которые мы создали в прошлой главе. Наша цель в данный момент — показать вам, как шаблонная система работает независимо от остальной части Django. (Предположим другой способ: обычно вы будете использовать шаблонную систему совместно с представлениями, но мы желаем показать то, что шаблонная система является обычной библиотекой Python, которую вы можете использовать где угодно, не только с представлениями Django.)
Ниже указан самый основной способ использования шаблонной системы Django в коде Python:
Создать объект
Template
, передав ему шаблон в виде строки.Вызвать метод
render()
объектаTemplate
с набором переменных (контекст). Метод возвратит полностью обработанный шаблон в виде строки, все переменные и шаблонные теги будут вычислены в соответствии с контекстом.
Пример использования:
>>> from django import template
>>> t = template.Template('My name is {{ name }}.')
>>> c = template.Context({'name': 'Adrian'})
>>> print t.render(c)
My name is Adrian.
>>> c = template.Context({'name': 'Fred'})
>>> print t.render(c)
My name is Fred.
Следующие разделы описывают каждый шаг более детально.
Простейшим способом создания объекта
Template
является его прямое
порождение. Класс Template
расположен в
модуле django.template, конструктор принимает единственный аргумент — строку с кодом шаблона. Давайте
рассмотрим как это всё работает с помощью интерактивного
интерпретатора языка Python.
В каталоге проекта mysite, созданном с помощью команды django-admin.py startproject (это было описано в главе «Начинаем»), выполните команды python manage.py shell для запуска интерактивного интерпретатора.
Пример интерактивной интерпретации
Если вы использовали Python ранее, вас может заинтересовать, почему мы используем python manage.py shell, а не просто python. Обе команды запускают интерпретатор, но наш вариант имеет одну ключевую особенность: перед запуском интерпретатора, он указывает Django какой файл конфигурации следует использовать. Многие компоненты Django, включая шаблонную систему, зависят от ваших настроек и вы не сможете их использовать до тех пор, пока среда разработки не будет знать где их брать.
Если вам это интересно, расскажем как всё это работает
внутри. Django ищет переменную среды с именем
DJANGO_SETTINGS_MODULE
, которая должна
содержать путь к вашему файлу
settings.py
. Например,
DJANGO_SETTINGS_MODULE
может быть
установлено в mysite.settings,
подразумевая, что каталог mysite
находится в пути Python.
При запуске python manage.py shell
настройка DJANGO_SETTINGS_MODULE
производится автоматически. Мы рекомендуем использовать
данный метод для работы с приведёнными ниже примерами.
После того, как вы лучше изучите Django, вероятно вы
перестанете использовать данный способ и будете
устанавливать DJANGO_SETTINGS_MODULE
вручную в вашем .bash_profile
или в
другом конфигурационном файле вашей среды.
Рассмотрим основы шаблонной системы:
>>> from django.template import Template
>>> t = Template('My name is {{ name }}.')
>>> print t
Если вы попробовали запустить данный код в интерпретаторе, то вы увидели нечто подобное:
<django.template.Template object at 0xb7d5f24c>
Шестнадцатеричный адрес объекта —
0xb7d5f24c будет всякий раз разным, не
обращайте на это внимание. Это внутренняя информация Python,
так называемый «идентификатор» созданного объекта
Template
.
При создании объекта Template
шаблонная
система компилирует строку с кодом шаблона во внутренний
оптимизированный формат, готовый для обработки. Но если ваш
шаблонный код содержит синтаксические ошибки, вызов
Template()
приведёт к исключению
TemplateSyntaxError
:
>>> from django.template import Template
>>> t = Template('{% notatag %}')
Traceback (most recent call last):
File "<stdin>", line 1, in ?
...
django.template.TemplateSyntaxError: Invalid block tag: 'notatag'
Термин «block tag[7]» в данном случае относится к {% notatag %}. «Блочный тег» и «шаблонный тег» являются синонимами.
Система вызывает исключение
TemplateSyntaxError
в любом из
нижеприведённых случаев:
Неверные теги;
Неверные аргументы у верных тегов;
Неверные фильтры;
Неверные аргументы у верных фильтров;
Неверный синтаксис шаблона;
Незакрытые теги (для тегов, которые требуют наличия завершающих тегов).
После того, как объект Template
создан,
вы можете передавать ему данные через
контекст. Контекстом называют набор
значений, ассоциированных с шаблонными переменными. Шаблон
использует контекст для замены шаблонных переменных на
значения и для вычисления тегов.
Контекст в Django представлен классом
Context
, который определён в модуле
django.template. Конструктор этого класса принимает один необязательный аргумент — словарь,
содержащий имена переменных и ассоциированные им
значения. Вызовите метод render()
объекта
Template
для заполнения шаблона
контекстными значениями:
>>> from django.template import Context, Template
>>> t = Template('My name is {{ name }}.')
>>> c = Context({'name': 'Stephane'})
>>> t.render(c)
u'My name is Stephane.'
Единственное, о чём следует упомянуть — то, что значение
t.render(c) является объектом
Unicode
, а не обычной строкой
Python. Вы можете выразить это, добавив u перед
строкой. Django везде использует объекты
Unicode
вместо обычных строк. Если вы
не понимаете последствия этого подхода, не
беспокойтесь. Просто запомните, что поддержка Unicode
позволяет упростить для вашего приложения поддержку
национальных языков.
Словари и контексты
Словарь в языке Python является отображением между
известным набором ключей и их
значений. Context
подобен словарю,
но он также предоставляет дополнительный функционал,
который описан в главе 9 FIXME.
Имена переменных должны начинаться с буквы (A-Z или a-z) и могут состоять из множества букв, цифр, символов подчёркивания и точек. (Точки являются особым случаем, мы скоро рассмотрим их.) Имена переменных регистрозависимы.
Ниже показан пример компиляции и обработки шаблона, который похож на тот, что мы рассмотрели в начале главы:
>>> from django.template import Template, Context
>>> raw_template = """<p>Dear {{ person_name }},</p>
...
... <p>Thanks for placing an order from {{ company }}. It's scheduled to
... ship on {{ ship_date|date:"F j, Y" }}.</p>
...
... {% if ordered_warranty %}
... <p>Your warranty information will be included in the packaging.</p>
... {% else %}
... <p>You didn't order a warranty, so you're on your own when
... the products inevitably stop working.</p>
... {% endif %}
...
... <p>Sincerely,<br />{{ company }}</p>"""
>>> t = Template(raw_template)
>>> import datetime
>>> c = Context({'person_name': 'John Smith',
... 'company': 'Outdoor Equipment',
... 'ship_date': datetime.date(2009, 4, 2),
... 'ordered_warranty': False})
>>> t.render(c)
u"<p>Dear John Smith,</p>\n\n<p>Thanks for placing an order from Outdoor
Equipment. It's scheduled to\nship on April 2, 2009.</p>\n\n\n<p>You
didn't order a warranty, so you're on your own when\nthe products
inevitably stop working.</p>\n\n\n<p>Sincerely,<br />Outdoor Equipment
</p>"
Рассмотрим каждую строку кода:
Сначала мы импортируем классы
Template
иContext
, которые определены в модуле django.template.Мы сохраняем оригинальный текст нашего шаблона в переменной
raw_template
. Следует отметить, что мы используем тройные кавычки для выделения строки, так как мы имеем дело с многострочной строкой. Дело в том, что строки, заключённые в одинарные кавычки, не могут быть многострочными.Затем мы создаём шаблонный объект, t, передавая
raw_template
в конструктор классаTemplate
.Мы импортируем модуль datetime из стандартной библиотеки Python, так как нам он понадобится в дальнейшем.
Затем мы создаём контекстный объект, c. Конструктор класса
Context
принимает словарь, который содержит ассоциированные именам значения. В нашем случае, мы определили, чтоperson_name
имеет значение 'John Smith',company
— 'Outdoor Equipment' и так далее.В конце мы вызвали метод
render()
для нашего шаблонного объекта, передав ему контекст. Нам был возвращён обработанный шаблон, т.е., метод заменил переменные их действительными значениями и вычислил все шаблонные теги.Следует отметить, что параграф «You didn’t order a warranty» был отображён, потому что переменная
ordered_warranty
вычислилась в False. Обратите внимание на дату, April 2, 2009, которая отобразилась в соответствии с заданным форматом — 'F j, Y'. (Мы расскажем об аргументах фильтраdate
немного позже.)Если вы новичок в Python, вы можете заинтересоваться почему результат содержит символы перевода строки (\n), вместо того, чтобы отображать реальные переводы строк. Так происходит из-за тонкостей работы интерактивного интерпретатора Python: вызов t.render(c) возвращает строку и, по умолчанию, интерактивный интерпретатор отображает представление строки, вместо печатного варианта строки. Если вы желаете получить печатную строку, используйте оператор
print
: print t.render(c).
Таковы основы использования шаблонной системы Django: просто
напишите шаблонную строку, создайте объект
Template
, создайте
Context
и вызовите метод
render()
.
После того, как вы создали объект
Template
, вы можете с его помощью
обработать множество контекстов. Например:
# Так делать не стоит
for name in ('John', 'Julie', 'Pat'):
t = Template('Hello, {{ name }}')
print t.render(Context({'name': name}))
# Правильный подход
t = Template('Hello, {{ name }}')
for name in ('John', 'Julie', 'Pat'):
print t.render(Context({'name': name}))
Django обрабатывает шаблон достаточно быстро. Внутри всё это сводится к вызову единственного регулярного выражения. Это сильно контрастирует по отношению к шаблонным движкам, построенным на XML, которые вносят затраты на разбор XML и по скорости проигрывают шаблонной системе Django.
В вышеприведённых примерах мы передавали простые значения в контекст, в основном это были строки, иногда даты. Тем не менее, шаблонная система легко обрабатывает более сложные структуры данных, такие как списки, словари и различные объекты.
Ключом к такой всеядности является символ . (точка). Используйте точку для получения доступа к ключам словаря, атрибутам, методам и индексам объекта.
Это хорошо проиллюстрировано в нескольких примерах. Например, предположим, что вы передали словарь в шаблон. Для получения доступа к значениям этого словаря по ключу следует использовать точку:
>>> from django.template import Template, Context
>>> person = {'name': 'Sally', 'age': '43'}
>>> t = Template('{{ person.name }} is {{ person.age }} years old.')
>>> c = Context({'person': person})
>>> t.render(c)
u'Sally is 43 years old.'
Аналогично, точка также позволяет получить доступ к атрибутам
объекта. Например, объект datetime.date
содержит атрибуты year, month и
day, и вы можете получить к ним доступ:
>>> from django.template import Template, Context
>>> import datetime
>>> d = datetime.date(1993, 5, 2)
>>> d.year
1993
>>> d.month
5
>>> d.day
2
>>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.')
>>> c = Context({'date': d})
>>> t.render(c)
u'The month is 5 and the year is 1993.'
Следующий пример использует класс, демонстрируя методику получения доступа к атрибутам объекта:
>>> from django.template import Template, Context
>>> class Person(object):
... def __init__(self, first_name, last_name):
... self.first_name, self.last_name = first_name, last_name
>>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.')
>>> c = Context({'person': Person('John', 'Smith')})
>>> t.render(c)
u'Hello, John Smith.'
С помощью точек можно получать доступ к
методам объектов. Например, каждая строка
Python обладает методами upper()
и
isdigit()
, и вы можете использовать их в
шаблонной системе Django с помощью «точечного»
синтаксиса:
>>> from django.template import Template, Context
>>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}')
>>> t.render(Context({'var': 'hello'}))
u'hello -- HELLO -- False'
>>> t.render(Context({'var': '123'}))
u'123 -- 123 -- True'
Следует отметить, что не следует завершать имя метода скобками. Также нет никакой возможности передать аргументы в методы, вы можете использовать только те методы, которые не требуют аргументов. (Мы объясним такой подход немного позже в этой главе.)
Наконец, точки используются для доступа к элементам списка по индексу, например:
>>> from django.template import Template, Context
>>> t = Template('Item 2 is {{ items.2 }}.')
>>> c = Context({'items': ['apples', 'bananas', 'carrots']})
>>> t.render(c)
u'Item 2 is carrots.'
Отрицательные значения индекса не допускаются. Например,
шаблонная переменная {{ items.-1 }} вызовет
исключение TemplateSyntaxError
.
Списки в Python
Запомните: индексирование элементов списка в Python начинается с нуля. Первый элемент имеет индекс 0, второй — 1 и так далее.
Использование «точечного» синтаксиса можно описать так, когда шаблонная система обнаруживает точку в имени переменной, она пытается выполнить следующие действия в указанном порядке:
Поиск в словаре (т.е., foo["bar"]);
Поиск атрибута (т.е., foo.bar);
Вызов метода (т.е., foo.bar());
Поиск в списке по индексу (т.е., foo[2]).
Система использует первое, что сработает.
«Точечный» поиск может быть
многоуровневым. Например, в следующем примере используется
переменная {{ 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. Если исключение имеет атрибутsilent_variable_failure
, переменная будет преобразовываться в пустую строку, например:>>> t = Template("My name is {{ 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'My name is .'
Вызов метода срабатывает только в случае, если метод не требует наличия аргументов. В противном случае, система попробует следующий тип поиска (поиск в списке по индексу).
Очевидно, что некоторые методы будут иметь побочные эффекты и, в лучшем случае, было бы глупо давать шаблонной системе доступ к ним.
Например, у вас есть объект
BankAccount
, у которого есть методdelete()
. Если шаблон содержит что-то аналогичное {{ account.delete }}, где account — это объектBankAccount
, то объект будет удалён во время обработки шаблона!Чтобы сделать такое невозможным, установите для этого метода атрибут alters_data:
def delete(self): # Delete the account delete.alters_data = True
Шаблонная система не будет выполнять метод, помеченный таким образом. Продолжая обсуждение вышеприведённого примера, если шаблон содержит {{ account.delete }} и метод
delete()
имеет alters_data=True, то методdelete()
не будет выполнен при обработке шаблона, он будет просто проигнорирован.
По умолчанию, если переменная не существует, шаблонная система отобразит такую переменную как пустую строку. Например:
>>> from django.template import Template, Context
>>> t = Template('Your name is {{ name }}.')
>>> t.render(Context())
u'Your name is .'
>>> t.render(Context({'var': 'hello'}))
u'Your name is .'
>>> t.render(Context({'NAME': 'hello'}))
u'Your name is .'
>>> t.render(Context({'Name': 'hello'}))
u'Your name is .'
Система просто игнорирует такие шаблонные переменные, не вызывая исключение, потому что она должна быть устойчивой к человеческим ошибкам. В данном случае все «точечные» проверки будут неудачными. В случае настоящего приложения недопустимо, чтобы web-сайт стал недоступным из-за маленькой ошибки в шаблоне.
Большую часть времени, вы будете создавать объекты
Context
передавая готовый словарь в
Context()
. Но вы можете добавлять и
удалять элементы из объекта Context
после его создания, используя стандартный синтаксис словаря
Python:
>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c['foo']
'bar'
>>> del c['foo']
>>> c['foo']
Traceback (most recent call last):
...
KeyError: 'foo'
>>> c['newvariable'] = 'hello'
>>> c['newvariable']
'hello'
Пред. | Уровень выше | След. |
Глава 4. Шаблоны | Начало | Основные шаблонные теги и фильтры |
4 comments | Make a comment
Мда, к сожалению эта важная глава самая непоследовательная, сложная и запутанная из прочтенных... ИМХО, весь материал по методам и точечной нотации так и просится в отдельную главу, скажем, в изложении перед 4й главой. (Претензии понятно не к переводу, а к ув. Автору книги.:))
Вроде всё прозрачно и понятно, требуется понятие списков и строк Питона
При команде:
t = template.Template('My name is {{ name }}.')
Python 2.7.3 выдает ошибку =(
>>> t = template.Template('My name is {{ name }}.')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\django\template\base.py", line 123, in __i
nit__
if settings.TEMPLATE_DEBUG and origin is None:
File "C:\Python27\lib\site-packages\django\utils\functional.py", line 184, in
inner
self._setup()
File "C:\Python27\lib\site-packages\django\conf\__init__.py", line 40, in _set
up
raise ImportError("Settings cannot be imported, because environment variable
%s is undefined." % ENVIRONMENT_VARIABLE)
ImportError: Settings cannot be imported, because environment variable DJANGO_SE
TTINGS_MODULE is undefined.
Что делать?
answer to sotnikov.nk
При команде:
t = template.Template('My name is {{ name }}.')
Python 2.7.3 выдает ошибку =(
>>> t = template.Template('My name is {{ name }}.')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\lib\site-packages\django\template\base.py", line 123, in __i
nit__
if settings.TEMPLATE_DEBUG and origin is None:
File "C:\Python27\lib\site-packages\django\utils\functional.py", line 184, in
inner
self._setup()
File "C:\Python27\lib\site-packages\django\conf\__init__.py", line 40, in _set
up
raise ImportError("Settings cannot be imported, because environment variable
%s is undefined." % ENVIRONMENT_VARIABLE)
ImportError: Settings cannot be imported, because environment variable DJANGO_SE
TTINGS_MODULE is undefined.
Что делать?
Вопросы задавайте на форуме.