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

Django_-_podrobnoe_rukovodstvo

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

4

Шаблоны­

Возможно, вас удивил способ, которым мы возвращали текст в примерах представлений из предыдущей главы. Мы встраивали HTML-раз­ метку прямо в код на Python, например:

def current_datetime(request): now = datetime.datetime.now()

html = “<html><body>Сейчас %s.</body></html>” % now return HttpResponse(html)

Хотя это удобно, когда нужно объяснить, как работают представления, но, вообще говоря, «зашивать» HTML-разметку непосредственно в представление – порочная идея. И вот почему.

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

•• Программирование на Python и дизайн на HTML – разные виды деятельности, и в большинстве коллективов, профессионально занимающихся веб-разработкой, за них отвечают разные люди (и даже разные подразделения). От дизайнеров и верстальщиков на HTML/ CSS нельзя требовать умения редактировать код на Python.

•• Работа выполняется наиболее эффективно, когда программисты могут трудиться над программным кодом, а дизайнеры – над шаб­ лонами одновременно, не дожидаясь, пока кто-то закончит редактировать единственный файл, содержащий и код на Python, и разметку.

Поэтому было бы гораздо элегантнее и удобнее для сопровождения отделить дизайн страницы от ее кода на Python. Система шаблонов­ Django, которую мы обсудим в этой главе, как раз и позволяет это сделать.

Принципы работы системы­ шаблонов­

61

Принципы работы системы­ шаблонов­

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

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

<html>

<head><title>Извещение о сделанном заказе</title></head>

<body>

<h1> Извещение о сделанном заказе</h1>

<p>Уважаемый(ая) {{ person_name }}!</p>

<p>Спасибо, что вы сделали заказ в {{ company }}. Он будет доставлен вам {{ ship_date|date:”F j, Y” }}.</p>

<p>Ниже перечислены заказанные вами товары:</p>

<ul>

{% for item in item_list %} <li>{{ item }}</li>

{% endfor %} </ul>

{% if ordered_warranty %}

<p>Сведения о гарантийных обязательствах вы найдете внутри упаковки.</p> {% else %}

<p>Вы не заказывали гарантию, поэтому должны будете действовать самостоятельно, когда изделие неизбежно выйдет из строя.</p>

{% endif %}

<p>С уважением,<br />{{ company }}</p>

</body>

</html>

По существу, этот шаблон­ представляет собой HTML-разметку, в которую были добавлены переменные и шаблонные­ теги. Рассмотрим его более подробно.

•• Любой текст, окруженный парой фигурных скобок (например, {{ person_name }}) – это переменная. Такая конструкция означает, что нужно вставить значение переменной с указанным именем. Как задаются значения переменных? Скоро дойдем и до этого.

62

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

•• Любой текст внутри фигурных скобок со знаками процента (например, {% if ordered_warranty %}) – шабл­онный тег. Определение тега достаточно широкое: тег просто говорит системе,­ что нужно «сделать нечто».

В данном примере шаблон­ содержит тег for ({% for item in item_list %}) и тег if ({% if ordered_warranty %}).

Тег for очень похож на инструкцию for языка Python, то есть позволяет выполнить обход всех элементов последовательности. Тег if, как нетрудно догадаться, действует как условная инструкция «if». В данном случае этот тег проверяет, совпадает ли значение переменной ordered_warranty с True. Если да, то система­ шаблонов­ выведет весь текст между {% if ordered_warranty %} и {% else %}. Если нет, то будет выведен текст между {% else %} и {% endif %}. Отметим, что ветвь {% else %} необязательна.

•• Во втором абзаце этого шаблона­ встречается еще и фильтр – самый удобный способ отформатировать переменную. В данном случае он выглядит следующим образом: {{ ship_date|date:”F j, Y” }}. Мы передаем переменную ship_date фильтру date с аргументом “F j, Y”. Фильтр date форматирует даты в соответствии с форматом, заданным в аргументе. Фильтры присоединяются с помощью символа вертикальной черты (|), который служит напоминанием о конвейерах UNIX.

Каждый шаблон­ Django имеет доступ к нескольким встроенным тегам

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

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

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

Сейчас мы приступим к изучению системы­ шаблонов,­ но пока не станем интегрировать ее с созданными в предыдущей главе представлениями. Наша цель – показать, как работает система­ шаблонов­ вне связи с другими частями фреймворка Django. (Обычно шаблоны­ используются совместно с представлениями, но мы хотим, чтобы вы поняли, что сис­ тема шаблонов­ – просто библиотека на Python, применимая повсюду, а не только в представлениях Django.)

Вот как выглядит самый простой способ использования системы­ шаб­ лонов Django в коде на Python:

1.Создаем объект Template, передав код шаблона­ в виде строки.

2.Вызываем метод render() объекта Template с заданным набором переменных (контекстом). Метод возвращает результат обработки шаб­ лона в виде строки, в которой все переменные и шаблонные­ теги вычислены согласно переданному контексту.

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

63

Вкоде это выглядит следующим образом:

>>>from django import template

>>>t = template.Template(‘Меня зовут {{ name }}.’)

>>>c = template.Context({‘name’: ‘Адриан’})

>>>print t.render(c)

Меня зовут Адриан.

>>>c = template.Context({‘name’: ‘Фред’})

>>>print t.render(c)

Меня зовут Фред.

В следующих разделах эти шаги описываются гораздо более подробно.

Создание объектов Template

Проще всего создать объект Template непосредственно. Класс Template находится в модуле django.template, его конструктор принимает единственный аргумент – код шаблона­. Запустим интерактивный интерпретатор Python и посмотрим, как это работает в конкретной программе.

Находясь в каталоге проекта mysite, созданного командой django-admin. py startproject (см. главу 2), выполните команду python manage.py shell, чтобы войти в интерактивный интерпретатор.

Специальное приглашение Python

Если вы работали с Python раньше, то может возникнуть вопрос, почему нужно запускать оболочку командой python manage.py shell, а не просто python. Та и другая запускают интерактивный интерпретатор, но у команды manage.py shell есть одно важное отличие: до запуска интерпретатора она сообщает Django о том, какой файл параметров следует использовать. От этих параметров зависят многие части фреймворка Django, в том числе система­ шаб­ лонов, и, чтобы ими можно было воспользоваться, фреймворк должен знать, откуда взять параметры.

Для тех, кому интересно, расскажем, что происходит за кулисами. Django ищет переменную окружения DJANGO_SETTINGS_MODULE, значением которой должен быть путь импорта для файла settings. py. Например, DJANGO_SETTINGS_MODULE может быть равна ‘mysite. settings’ в предположении, что mysite включен в путь Python.

Если оболочка запускается командой python manage.py shell, то она берет на себя все хлопоты по установке значения переменной DJANGO_SETTINGS_MODULE. Мы рекомендуем во всех примерах использовать команду manage.py shell, чтобы избавить себя от необходимости самостоятельно задавать конфигурацию.

64

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

Когда вы получше освоитесь с Django, то, наверное, перестанете использовать команду manage.py shell и будете устанавливать переменную 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 каждый раз будет печататься новое значение, но оно несущественно (это просто внутренний идентификатор объекта 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 (блочный тег) относятся к тегу {% notatag %}. Выражения

блочный тег и шабл­онный тег – синонимы.

Система возбуждает исключение TemplateSyntaxError в следующих случаях:

•• Недопустимый тег

•• Недопустимые аргументы допустимого тега

•• Недопустимый фильтр

•• Недопустимые аргументы допустимого фильтра

•• Недопустимый синтаксис шаблона­

•• Незакрытые теги (если требуется наличие закрывающего тега)

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

65

Отображение шаблона­

Объекту Template можно передать данные в виде контекста. Контекст – это просто набор именованных переменных шаблона­ вместе с их значениями. Шаблон­ использует контекст, чтобы инициализировать свои переменные и вычислить теги.

В Django контекст представляется классом Context, который находится

вмодуле django.template. Его конструктор принимает один необязательный параметр – словарь, отображающий имена переменных в их значения. Вызовем метод render() объекта Template, передав ему контекст для

«заполнения» шаблона:­

>>>from django.template import Context, Template

>>>t = Template(‘Меня зовут {{ name }}.’)

>>>c = Context({‘name’: ‘Стефан’})

>>>t.render(c)

u’Меня зовут Стефан.’

Подчеркнем, что метод t.render(c) возвращает объект Unicode, а не обычную строку Python. Это видно по наличию буквы u перед строкой. Объекты Unicode используются вместо строк повсюду в фреймворке Django. Если вы понимаете, к каким последствиям это приводит, то благодарите Django за все те ухищрения, на которые он идет, чтобы все работало правильно. А если не понимаете, то и не забивайте себе голову; просто помните, что поддержка Unicode в Django позволяет приложениям относительно безболезненно работать с разнообразными наборами символов, помимо обычной латиницы.

Словари и контексты

ВязыкеPythonсловаремназываетсяотображениемеждуключами

изначениями. Объект Context похож на словарь, но обладает дополнительной функциональностью, которая рассматривается в главе 9.

Имя переменной должно начинаться с буквы (A–Z или a–z) и может содержать буквы, цифры, знаки подчеркивания и точки. (Точки – это особый случай, который мы обсудим в разделе «Поиск контекстных переменных».) Строчные и заглавные буквы в именах переменных считаются различными.

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

>>>from django.template import Template, Context

>>>raw_template = “””<p>Уважаемый(ая) {{ person_name }},</p>

...

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

... <p>Спасибо, что вы сделали заказ в {{ company }}. Он будет

... доставлен вам {{ ship_date|date:”F j, Y” }}.</p>

...

... {% if ordered_warranty %}

... <p> Сведения о гарантийных обязательствах вы найдете внутри упаковки.</p>

... {% else %}

... <p> Вы не заказывали гарантию, поэтому должны будете действовать самостоятельно, когда изделие неизбежно выйдет из строя.</p>

... {% endif %}

...

... <p>С уважением,<br />{{ company }}</p>”””

>>>t = Template(raw_template)

>>>import datetime

>>>c = Context({‘person_name’: ‘Джон Смит’,

... ‘company’: ‘Outdoor Equipment’,

... ‘ship_date’: datetime.date(2009, 4, 2),

... ‘ordered_warranty’: False})

>>>t.render(c)

u”<p> Уважаемый(ая) Джон Смит,</p>\n\n<p> Спасибо, что вы сделали заказ в Outdoor Equipment. Он будет\n доставлен вам April 2, 2009.</p>\n\n\n<p> Вы не заказывали гарантию, поэтому должны будете действовать \n самостоятельно, когда изделие неизбежно выйдет из строя.</p>\n\n\n<p>

С уважением,<br />Outdoor Equipment </p>”

Рассмотрим этот код по частям:

1.Сначала из модуля django.template импортируются классы Template

и Context.

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

3.Далее мы создаем объект шаблона­ t, передавая raw_template конструктору класса Template.

4.Импортируем модуль datetime из стандартной библиотеки Python, поскольку он понадобится в следующей инструкции.

5.Создаем объект с класса Context. Конструктор класса Context принимает словарь Python, который отображает имена переменных в их значения. Так, мы указываем, что переменная person_name содержит значение ‘Джон Смит’, переменная company – значение ‘Outdoor Equipment’ и так далее.

6.Наконец, мы вызываем метод render(), передавая ему контекст. Он возвращает результат отображения шаблона,­ в котором шаблонные­ переменные заменены фактическими значениями и обработаны все шаблонные­ теги.

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

67

Отметим, что выведен абзац «Вы не заказывали гарантию», поскольку переменная ordered_warranty равна False. Также отметим, что дата April 2, 2009 отформатирована в соответствии с форматом ‘F j, Y’. (Спецификаторы формата для фильтра date описываются в приложении E.)

У человека, не знакомого с языком Python, может возникнуть вопрос, почему, вместо того, чтобы просто разрывать строки, мы выводим символы перевода строки (‘\n’). Это объясняется одной тонкостью в интерактивном интерпретаторе Python: вызов метода t.render(c) возвращает строку, а интерактивный интерпретатор по умолчанию выводит представление строки, а не ее истинное значение. Если вы хотите увидеть, где разрываются строки, то воспользуйтесь инструкцией print: print t.render(c).

Вот вы и познакомились с основами использования системы­ шаблонов­ в Django: пишем исходный код шаблона,­ создаем объект Template, создаем объект Context и вызываем метод render().

Один шаблон,­ несколько контекстов

Существующий объект Template можно использовать для отображения нескольких контекстов. Рассмотрим следующий пример:

>>>from django.template import Template, Context

>>>t = Template(‘Привет, {{ name }}’)

>>>print t.render(Context({‘name’: ‘Джон’})) Привет, Джон

>>>print t.render(Context({‘name’: ‘Джулия’})) Привет, Джулия

>>>print t.render(Context({‘name’: ‘Пэт’})) Привет, Пэт

Когда один и тот же исходный шаблон­ необходимо использовать для отображения нескольких контекстов, эффективнее создать один объект Template и несколько раз вызвать его метод render():

# Так плохо

for name in (‘Джон’, ‘Джулия’, ‘Пэт’): t = Template(‘Hello, {{ name }}’)

print t.render(Context({‘name’: name}))

# А так хорошо

t = Template(‘Hello, {{ name }}’)

for name in (‘Джон’, ‘Джулия’, ‘Пэт’): print t.render(Context({‘name’: name}))

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

68

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

работу анализатора XML оказываются на несколько порядков медленнее механизма отображения шаблонов­ в Django.

Поиск контекстных переменных

В приведенных выше примерах мы передавали в контексте простые переменные – в основном строки да еще дату. Однако система­ шаблонов­ способна элегантно обрабатывать и более сложные структуры данных – списки, словари и пользовательские объекты.

Ключом к обработке сложных структур данных в шаблонах­ Django является знак точки (.). Точка позволяет получить доступ к словарю по ключу, к элементам списка по индексу, а также к атрибутам и методам объекта.

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

>>>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, и для доступа

кним из шаблона­ Django можно воспользоваться точкой, как показано ниже:

>>>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(‘Месяц равен {{ date.month }}, а год равен {{ date.year }}.’)

>>>c = Context({‘date’: d})

>>>t.render(c)

u’Месяц равен 5, а год равен 1993.’

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

>>>from django.template import Template, Context

>>>class Person(object):

... def __init__(self, first_name, last_name):

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

69

...

self.first_name, self.last_name = first_name, last_name

 

>>>t = Template(‘Привет, {{ person.first_name }} {{ person.last_name }}.’)

>>>c = Context({‘person’: Person(‘Джон’, ‘Смит’)})

>>>t.render(c)

u’Привет, Джон Смит.’

Спомощью точки можно также вызывать методы объектов. Например,

улюбой строки 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(‘Элемент 2 – {{ items.2 }}.’)

>>>c = Context({‘items’: [‘яблоки’, ‘бананы’, ‘морковки’]})

>>>t.render(c)

u’Элемент 2 - морковки.’

Отрицательные индексы не допускаются. Например, обращение к шаб­ лонной переменной {{ items.-1 }} приведет к исключению TemplateSyntax­­ Error.

Списки в языке Python

Напомним, что в языке Python нумерация элементов списка начинается с 0. Индекс первого элемента равен 0, второго – 1 и т. д.

Когда система­ встречает в шаблоне­ точку в имени переменной, она производит поиск подходящей переменной в следующем порядке:

•• Доступ к словарю (например, foo[“bar”])

•• Доступ к атрибуту (например, foo.bar)

•• Вызов метода (например, foo.bar())

•• Доступ к списку по индексу (например, foo[2])

Поиск останавливается, как только будет найдено первое подходящее имя.

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