Предыдущая часть.
Django предоставляет мощный и удобный API для загрузки шаблонов из файловой системы, цель которого – избавиться от избыточного кода в в вызовах шаблонов и в самих шаблонах.
Для того, что бы использовать этот API – вы должны указать фреймворку, где именно он должен искать файлы шаблонов. Сделать это можно в файле настроек вашего проекта – settings.py
, который уже упоминался в первой главе, когда мы рассматривали настройку URLconf
и параметр ROOT_URLCONF
.
Откройте ваш файл settings.py
в каталоге проекта, и найдите строку TEMPLATE_DIRS
. По умолчанию она пустая, и содержит только несколько комментариев:
TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. )
Тут указывается, где система шаблонов Django где ей искать файлы шаблонов. Найдите директорию, в которой вы хотите их хранить, и укажите её в параметре TEMPLATE_DIRS
, например:
TEMPLATE_DIRS = ( '/var/www/django/example/templates' )
Несколько моментов, которые надо помнить:
-
Вы можете указать любую директорию, главное что бы она и файлы шаблонов в ней были доступны на чтение вашему веб-серверу. Если вы не можете придумать подходящую – то мы бы рекомендовали вам создать директорию
templates
в каталоге вашего проекта. -
Если параметр
TEMPLATE_DIRS
содержит только один каталог – не забудьте добавить запятую после указания пути.Плохой вариант:
# Missing comma! TEMPLATE_DIRS = ( '/home/django/mysite/templates' )
Хороший вариант:
# Comma correctly in place. TEMPLATE_DIRS = ( '/home/django/mysite/templates', )
Причина этого заключается в том, что для Python необходимо наличие запятых, что бы он мог отличить кортеж от выражений в скобках.
-
Если вы пользуетесь Windows – добавляйте имя диска и используйте Unix-like косые, вместо обратных:
TEMPLATE_DIRS = ( 'C:/www/django/templates', )
-
Лучше всего использовать полные пути от корня вашей файловой системы. Но если вы хотите иметь более гибкую систему – вы можете использовать тот факт, что файл настроек Django – это простой файл Python, и вы можете указать путь к директории шаблонов динамически, например так:
import os.path TEMPLATE_DIRS = ( os.path.join(os.path.dirname(__file__), 'templates').replace('\','/'), )
В этом примере используйется специальная переменная Python
__file__
, которая указывает на файл, из которого она вызывается. Тут берётся путь к директории, в которой находится файлsettings.py
(os.path.dirname
), к нему добавляетсяtemplates
с помощью кросс-платформенной функции (os.path.join
), затем все обратные слеши меняются на прямые (на случай использования под Windows).Так как вы теперь немного в курсе использования кода Python в файле настроек – мы должны предупредить вас, что необходимо быть очень осторожным и избегать ошибок Python в нём. Если вы допустите синтаксическую или другую ошибку – ваш сайт упадёт.
Теперь, когда вы настроили TEMPLATE_DIRS
, можно изменить само представление на использование системы загрузки шаблонов Django вместо того, что бы вписывать путь к шаблону прямо в код.
Вернёмся к нашему представлению current_datetime
, и изменим его так:
from django.template.loader import get_template from django.template import Context from django.http import HttpResponse, Http404 import datetime def current_datetime(request): now = datetime.datetime.now() t = get_template('timetemplate.html') html = t.render(Context({'current_date': now})) return HttpResponse(html)
В этом примере мы используем функцию django.template.loader.get_template()
вместо того, что бы загружать файл шаблона вручную. Функция get_template()
принимает имя шаблона первым аргументом, определяет где хранятся шаблоны в файловой системе, открывает этот файл и возвращает скомилированный объект Template
.
В нашем примере используется файл шаблона timetemplate.html
, но его расширение может быть любым, не обязательно .html
. Вы можете указать любое другое подходящее вам расширение – или не указывать его вообще.
Что бы определить расположение файла шаблона в файловой системе, get_template()
совмещает директорию шаблонов из настройки TEMPLATE_DIRS
и имя шаблона, переданное этой функции. Например, если ваш TEMPLATE_DIRS
указан в /var/www/django/example/templates
, то функция get_template()
будет искать файл /var/www/django/example/templates/timetemplate.html
.
Если get_template()
не сможет найти файл с заданным именем – она вызове исключение TemplateDoesNotExist
. Вот как он выглядит:
Эта страница схожа с той, которую мы рассматривали в статье Django Book: страница ошибки Django, с одним дополнительным полем информации – блок “Template-loader postmortem”. В нём описывается – какой именно шаблон Django пытался загрузить и детали неудачной попытки (например – “File does not exist”). Она окажет неоценимую помощь во время поиска причины, по которой шаблон не загружается.
Содержание
render()
Мы показали вам, как загрузить шаблон, заполнить Context
и вернуть объект HttpResponse
с результатом рендеринга шаблона. Мы оптимизировали этот процесс с использованием функции get_template()
вместо того, что указывать файл в коде напрямую. Однако, нам всё ещё требуется много печатать, что бы выполнить все эти действия.
Django предоставляет возможность уменьшить все эти действия – загрузить шаблон, выполнить рендеринг и вернуть HttpResponse
– всего одной строкой кода.
Эта возможность – функция с именем render()
из модуля django.shortcuts
. В основном вы будете пользоваться именно ей, вместо того, что бы выполнять все эти действия вручную – по крайней мере, если ваш работодатель не платит вам за количество строк кода, который вы пишете.
Вот наша функция current_datetime
, переписанная с использованием render()
:
from django.shortcuts import render import datetime def current_datetime(request): now = datetime.datetime.now() return render(request, 'timetemplate.html', {'current_date': now})
Чувствуете разницу? Давайте посмотрим какие изменения мы сделали:
- Мы больше не выполняем импорт
get_template
,Template
,Context
иHttpResponse
. Вместо этого мы импортируемdjango.shortcuts.render
.import datetime
остаётся. - Внутри функции
current_datetime
мы оставляем вычисление значения переменнойnow
, но убираем загрузку шаблона, создание контекста, рендеринг шаблона и созданиеHttpResponse
– теперь всем этим занимается функцияrender()
.
Первый аргумент для render()
– это request
, второй – имя шаблона. Третий аргумент, если указан – это словарь для создания контекста этого шаблона. Если его не указать – render()
будет использовать пустой словарь.
Вложенные каталоги в get_template()
Может быть неудобно хранить все ваши шаблоны в одной директории. Возможно, вы захотите поместить некоторые шаблоны во вложенные каталоги вашей директории templates
– и это можно сделать. Мы даже рекомендуем вам так поступать – некоторые более продвинутые возможности Django будут ожидать такого.
Хранить шаблоны во вложенных каталогах очень просто. В вашем вызове функции get_template()
просто укажите имя директории, слеш и имя файла шаблона, например так:
t = get_template('dateapp/current_datetime.html')
Так как render()
– это лишь маленькая обёртка вокруг get_template()
– вы можете сделать то же со вторым аргументом ей, например:
return render(request, 'dateapp/current_datetime.html', {'current_date': now})
Нет никаких ограничений на глубину вложенности каталогов.
Примечание
Пользователи Windows – помните про использование прямых слешей вместо обратных, так как get_template()
ожидает получить их в Unix-like виде.
Тег шаблонов include
Теперь, когда мы в целом разобрались с системой загрузки шаблонов, мы можем рассказать вам о встроенном теге {% include %}
, который даст вам дополнительные преимущества. Он позволяет включать содержимое одного шаблона в другой. Аргументом ему передаётся имя шаблона, который необходимо включить в основной шаблон, а имя может быть задано либо с помощью переменной – либо в виде строки, заключённой в кавычки. Каждый раз, когда вам приходится использовать один и тот же код в шаблонах – старайтесь пользоваться {% include %}
.
В этих двух примерах выполняется добавление шаблона nav.html
. Оба примера одинаковы – вы можете использовать как одинарные, так и двойные кавычки:
{% include 'nav.html' %} {% include "nav.html" %}
В этом примере выполняется добавление шаблона из вложенной директории:
{% include 'includes/nav.html' %}
В этом примере – подключается шаблон, чьё имя хранится в переменной template_name
:
{% include template_name %}
Как и в функции get_template()
имя файла определяется путём совмещения значения TEMPLATE_DIRS
и имени шаблона.
Вложенные шаблоны работают с теми же контекстами, с которыми создавался “вышестоящий” шаблон. Предположим, что у нас есть два шаблона:
# mypage.html <html> <body> {% include "includes/nav.html" %} <h1>{{ title }}</h1> </body> </html>
и:
# includes/nav.html <div id="nav"> You are in: {{ current_section }} </div>
При рендеринге mypage.html
с контекстом, содержащим переменную current_section
– она будет доступна из вложенного шаблона.
Если при использовании тега {% include %}
заданный шаблон не будет найден – Django поступит следующим образом:
- Если
DEBUG
включен – будет выдана ошибка TemplateDoesNotExist на странице ошибок Django; - Если
DEBUG
выключен – никаких сообщений не будет, а на месте тега будет пустое место.
Продолжение и последняя часть второй главы – Django Book: наследование в шаблонах.