Шаблоны Django
Шаблонная система Django (Template System) — это ключевой компонент, используемый для отделения бизнес-логики (Python) от уровня представления (HTML). Она позволяет разработчикам динамически генерировать HTML-страницы с помощью простых тегов и переменных.
В предыдущей главе мы использовалиdjango.http.HttpResponse()для вывода"Hello World!"Такой подход смешивает данные и представления вместе, что не соответствует философии MVT Django.
В этом разделе мы подробно рассмотрим применение шаблонов Django. Шаблон — это текст, используемый для отделения формы представления от содержания документа.
| Особенности | Синтаксис/Примеры | Применимые сценарии |
|---|---|---|
| Рендеринг переменных | {{ variable }} | Динамическое отображение данных |
| Управление логикой | {% if %}, {% for %} | Условный/циклический рендеринг |
| Наследование шаблонов | {% extends %}, {% block %} | Избегание дублирования HTML-структур |
| Статические файлы | {% static 'path' %} | Загрузка CSS/JS/изображений |
| Пользовательские фильтры | @register.filter | Расширение функциональности шаблонов |
Примеры применения шаблонов
Продолжая проект из предыдущей главы, мы создадим каталог templates в каталоге HelloWorld и создадим файл example.html. Вся структура каталогов выглядит следующим образом:
HelloWorld/
|-- HelloWorld
| |-- __init__.py
| |-- __init__.pyc
| |-- settings.py
| |-- settings.pyc
| |-- urls.py
| |-- urls.pyc
| |-- views.py
| |-- views.pyc
| |-- wsgi.py
| `-- wsgi.pyc
|-- manage.py
`-- templates
`-- example.html
Код файла example.html выглядит следующим образом:
Код файла HelloWorld/templates/example.html:
Из шаблонов мы знаем, что переменные используют двойные фигурные скобки.{{ }}。
Далее нам нужно сообщить Django путь к файлу шаблона. Откройте файл HelloWorld/HelloWorld/settings.py и изменитеTEMPLATESвDIRSна[BASE_DIR / "templates"], как показано ниже:
Код файла HelloWorld/HelloWorld/settings.py:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / "templates"], # Изменить здесь
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
...
Теперь мы изменяем views.py, чтобы добавить новый объект для передачи данных в шаблон:
Код файла HelloWorld/HelloWorld/views.py:
Как видите, здесь мы используем render, чтобы заменить ранее использовавшийся HttpResponse. render также принимает словарь context в качестве параметра.
Пары ключ-значение элементов в словаре context.helloСоответствует переменным в шаблоне{{ hello }}。
Код файла HelloWorld/HelloWorld/urls.py:
Затем перейдите в каталог HelloWorld и выполните следующую команду, чтобы запустить сервер:
python3 manage.py runserver 0.0.0.0:8000
Посетите сноваhttp://127.0.0.1:8000/example, вы увидите страницу:

Таким образом, мы завершили использование шаблонов для вывода данных, тем самым достигнув разделения данных и представлений.
Далее мы подробно рассмотрим часто используемые правила синтаксиса в шаблонах.
Теги шаблонов Django
Синтаксис:
{% tag %}
Управление логикой шаблона, общие теги:
| Теги | Назначение |
|---|---|
{% for %} | Перебор списков/словарей |
{% if %} | Условные операторы |
{% extends %} | Наследование базового шаблона |
{% block %} | Определение блоков содержимого, которые могут быть переопределены дочерними шаблонами |
{% include %} | Встраивание других фрагментов шаблона |
{% url %} | Обратное разрешение URL (чтобы избежать жестко заданных путей) |
{% csrf_token %} | Генерация CSRF-токена (для POST-форм) |
Переменная
Синтаксис шаблона:
view:{"HTML变量名" : "views变量名"} HTML:{{变量名}}
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
views_name = "Example"
return render(request,"example.html", {"name":views_name})
example.html в папке templates:
<p>{{ name }}</p>

Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

Список
В файле example.html в папке templates вы можете использовать.чтобы получить соответствующий элемент по индексу.
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
views_list = ["Учебник для новичков 1","Учебник для новичков 2","Учебник для новичков 3"]
return render(request, "example.html", {"views_list": views_list})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

Словарь
В файле example.html в папке templates вы можете использовать.keyчтобы получить соответствующее значение.
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
views_dict = {"name":"Пример"}
return render(request, "example.html", {"views_dict": views_dict})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

Filter
Синтаксис шаблона:{{ Variable name | Filter: optional parameter }}
Фильтры шаблонов могут изменять переменную перед её отображением. Фильтры используют символ вертикальной черты, как показано ниже:
{{ name|lower }}
После обработки переменной {{ name }} фильтром lower текст преобразуется из верхнего регистра в нижний.
Каналы фильтров можно *объединять в цепочку*, то есть вывод одного канала фильтра может служить входом для следующего канала:
{{ my_list|first|upper }}
В приведённом выше примере берётся первый элемент и преобразуется в верхний регистр.
Некоторые фильтры имеют параметры. Параметры фильтра указываются после двоеточия и всегда заключаются в двойные кавычки. Например:
{{ bio|truncatewords:"30" }}
Это отобразит первые 30 слов переменной bio.
Другие фильтры:
- addslashes: Добавляет обратные слеши перед любыми обратными слешами, одинарными кавычками или двойными кавычками.
- date : Форматирует объект date или datetime в соответствии с указанным параметром строки формата. Пример:
{{ pub_date|date:"F j, Y" }} - length: возвращает длину переменной.
default
default предоставляет значение по умолчанию для переменной.
Если логическое значение переменной, переданной представлениями, равно false, используется указанное значение по умолчанию.
Следующие значения являются ложными:
0 0.0 False 0j "" [] () set() {} None
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
name =0
return render(request, "example.html", {"name": name})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

length
Возвращает длину объекта; применимо к строкам и спискам.
Для словаря возвращает количество пар ключ-значение; для множества возвращает длину после удаления дубликатов.
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
name ="Example"
return render(request, "example.html", {"name": name})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

filesizeformat
Отображает размер файла в более удобочитаемом формате (например, '13 KB', '4.1 MB', '102 bytes' и т. д.).
Для словаря возвращает количество пар ключ-значение; для множества возвращает длину после удаления дубликатов.
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
num=1024
return render(request, "example.html", {"num": num})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

date
Форматирует переменную даты в соответствии с заданным форматом.
ФорматированиеY-m-d H:i:sreturnYear-Month-Day Hour:Minute:Secondвремя в формате.
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
import datetime
now =datetime.datetime.now()
return render(request, "example.html", {"time": now})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

truncatechars
Если общее количество символов в строке превышает указанное число, конечная часть будет усечена.
Усечённая строка будет заканчиваться...окончанием.
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
views_str = "Example"
return render(request, "example.html", {"views_str": views_str})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

safe
Помечает строку как безопасную, и она не требует экранирования.
Используйте safe только тогда, когда можете гарантировать, что данные, переданные из views.py, абсолютно безопасны.
Он имеет тот же эффект, что и mark_safe в серверном views.py.
Django автоматически экранирует синтаксис тегов, переданный из views.py в HTML-файлы, из-за чего его семантика не срабатывает. Добавление фильтра safe сообщает Django, что данные безопасны и не нуждаются в экранировании, позволяя семантике данных вступить в силу.
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
views_str = "<a href='/index.html'>Нажмите, чтобы перейти</a>"
return render(request, "example.html", {"views_str": views_str})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

тег if/else
Базовый формат синтаксиса выглядит следующим образом:
{% if condition %}
... display
{% endif %}
Или:
{% if condition1 %}
... display 1
{% elif condition2 %}
... display 2
{% else %}
... display 3
{% endif %}
Определяет, выводить ли данные в зависимости от условий. if/else поддерживает вложенность.
Тег {% if %} принимает ключевые слова and, or, not для вычисления нескольких переменных или для отрицания переменной (not), например:
{% if athlete_list and coach_list %}
athletes 和 coaches 变量都是可用的。
{% endif %}
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
views_num = 88
return render(request, "example.html", {"num": views_num})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

тег 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>
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
views_list = ["Пример","Учебник для новичков 1","Учебник для новичков 2","Учебник для новичков 3",]
return render(request, "example.html", {"views_list": views_list})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

Добавьте reversed к тегу, чтобы список перебирался в обратном порядке:
{% for athlete in athlete_list reversed %}
...
{% endfor %}
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

Итерация по словарю: Вы можете напрямую использовать словарь.itemsМетод: используйте распаковку переменных, чтобы получить ключи и значения отдельно.
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
views_dict = {"name":"Пример","age":18}
return render(request, "example.html", {"views_dict": views_dict})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

- forloop.counter: Возвращает индекс цикла по порядку, начиная с 1.
- forloop.counter0: Возвращает индекс цикла по порядку, начиная с 0.
- forloop.revcounter: Возвращает индекс цикла в обратном порядке, при этом конечный индекс равен 1.
- forloop.revcounter0: Возвращает индекс цикла в обратном порядке, при этом последний индекс равен 0.
- forloop.first (обычно используется с тегом if): возвращает True для первого элемента, False для остальных.
- forloop.last (обычно используется с тегом if): возвращает True для последнего элемента, False для остальных.
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
views_list = ["a", "b", "c", "d", "e"]
return render(request, "example.html", {"listvar": views_list})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

{% empty %}
Необязательная конструкция {% empty %}: она выполняется, когда цикл пуст (т. е. когда логическое значение аргумента после in равно False).
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
views_list = []
return render(request, "example.html", {"listvar": views_list})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

Тег {% for %} может быть вложенным:
{% for athlete in athlete_list %}
<h1>{{ athlete.name }}</h1>
<ul>
{% for sport in athlete.sports_played %}
<li>{{ sport }}</li>
{% endfor %}
</ul>
{% endfor %}
Тег комментария
В Django комментарии используют {# #}.
{# This is a comment #}
тег include
Тег {% include %} позволяет включать содержимое других шаблонов в шаблон.
В следующем примере включается шаблон nav.html:
{% include "nav.html" %}
csrf_token
csrf_token используется в формах, а его функция — защита от межсайтовой подделки запросов.
Если не используется тег{% csrf_token %}: при использовании формы, если нужно снова перенаправить на страницу, будет выдана ошибка прав доступа 403.
При использовании тега{% csrf_token %}: это сработает только при отправке данных через форму.
Анализ:
Сначала отправьте запрос на сервер, чтобы получить страницу входа. В этот момент middleware csrf автоматически сгенерирует скрытый тег input. Атрибут value в этом теге — случайная строка. Когда пользователь получает страницу входа, он также получает этот скрытый тег input.
Затем, когда пользователю нужно использовать форму для отправки данных, он передаст этот тег input и отправит его в middleware CSRF. Причина в том, что когда форма отправляет данные, она включает все теги input. Когда middleware CSRF получает данные, он определяет, является ли эта случайная строка той, которую он отправил пользователю в первый раз. Если да, отправка данных успешна; если нет, возвращается ошибка прав доступа 403.
Пользовательские теги и фильтры
1. Создайте в каталоге приложенияtemplatetagsкаталог (на том же уровне, что и каталог templates, имя каталога может быть только templatetags).
HelloWorld/ |-- HelloWorld | |-- __init__.py | |-- __init__.pyc | |-- settings.py ... |-- manage.py `-- templatetags `-- templates
2. Создайте любой py-файл в каталоге templatetags, например:my_tags.py。
3. Код файла my_tags.py выглядит следующим образом:
from django import template register = template.Library() #register的名字是固定的,不可改变
Измените конфигурацию параметра TEMPLATES в файле settings.py и добавьте конфигурацию libraries:
Конфигурационный файл settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR, "/templates",],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
"libraries":{ # Добавьте эти три строки конфигурации здесь
'my_tags':'templatetags.my_tags' # Добавьте эти три строки конфигурации здесь
} # Добавьте эти три строки конфигурации здесь
},
},
]
...
4. Используйте декоратор @register.filter для определения пользовательского фильтра.
Примечание:Декоратор может иметь не более 2 параметров.
@register.filter
def my_filter(v1, v2):
return v1 * v2
5. Используйте декоратор @register.simple_tag для определения пользовательского тега.
@register.simple_tag
def my_tag1(v1, v2, v3):
return v1 * v2 * v3
6. Перед использованием пользовательских тегов и фильтров необходимо импортировать этот py-файл в самом начале body в HTML-файле.
{% load my_tags %}7. Используйте пользовательские фильтры в HTML.
{{ 11|my_filter:22 }}
8. Используйте пользовательские теги в HTML.
{% my_tag1 11 22 33 %}
9. Семантические теги
Импортируйте mark_safe в этом py-файле.
from django.utils.safestring import mark_safe
При определении тегов используйте метод mark_safe, чтобы сделать теги семантическими, что эквивалентно методу html() в jQuery.
Это даёт тот же эффект, что и фильтр safe в HTML-файлах фронтенда.
@register.simple_tag
def my_html(v1, v2):
temp_html = "<input type='text' id='%s' class='%s' />" %(v1, v2)
return mark_safe(temp_html)
Используйте этот пользовательский тег в HTML, чтобы динамически создавать теги на странице.
{% my_html "zzz" "xxx" %}
Настройка статических файлов
1. Создайте каталог statics в корневом каталоге проекта.

2. Добавьте следующую конфигурацию в нижней части файла settings:
STATIC_URL = '/static/' # 别名
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "statics"),
]
3. Создайте каталоги css, js, images и plugins в каталоге statics для хранения CSS-файлов, JS-файлов, изображений и плагинов соответственно.
4. Поместите фреймворк bootstrap в каталог plugins.
5. Подключите bootstrap в теге head HTML-файла.
Примечание:На этом этапе в пути ссылки следует использовать псевдоним static из файла конфигурации, а не каталог statics.
<link rel="stylesheet" href="../static/plugins/bootstrap-3.3.7/dist/css/bootstrap.css.html">
Чтобы использовать это в шаблонах, нужно добавить{% load static %}код. В следующем примере мы импортируем изображение из каталога static.
Код файла HelloWorld/HelloWorld/views.py:
def example(request):
name ="Example"
return render(request, "example.html", {"name": name})
Код файла HelloWorld/templates/example.html:
Снова посетите http://127.0.0.1:8000/example, и вы увидите страницу:

Наследование шаблонов
Шаблоны могут обеспечивать повторное использование через наследование, сокращая дублирующееся содержимое.
Содержимое верхнего и нижнего колонтитулов веб-страницы обычно одинаково, поэтому мы можем использовать наследование шаблонов для повторного использования.
Родительский шаблон используется для размещения повторно используемого содержимого, а дочерний шаблон наследует содержимое родительского шаблона и размещает собственное содержимое.
родительский шаблон
Тег block...endblock:Зарезервированные блоки в родительском шаблоне оставлены для того, чтобы дочерний шаблон заполнил их различающимся содержимым. Разные зарезервированные блоки не должны иметь одинаковое имя.
{% block 名称 %}
预留给子模板的区域,可以设置设置默认内容
{% endblock 名称 %}
дочерний шаблон
Дочерний шаблон использует тег extends для наследования родительского шаблона:
{% extends "父模板路径"%}
Если дочерний шаблон не задаёт содержимое зарезервированных блоков родительского шаблона, используется содержимое по умолчанию, заданное в родительском шаблоне. Конечно, вы также можете оставить их незаданными, и они будут пустыми.
Дочерний шаблон задаёт содержимое зарезервированных блоков родительского шаблона:
{ % block 名称 % }
内容
{% endblock 名称 %}
Затем мы сначала создаём файл base.html в каталоге templates предыдущего проекта. Код выглядит следующим образом:
Код файла HelloWorld/templates/base.html:
В приведённом выше коде блок с именем mainbody — это часть, которую могут заменить наследники.
Все теги {% block %} сообщают шаблонному движку, что дочерние шаблоны могут переопределять эти части.
В example.html наследуйте base.html и замените определённые блоки. Изменённый код example.html выглядит следующим образом:
Код файла HelloWorld/templates/example.html:
Первая строка кода указывает, что example.html наследует файл base.html. Видно, что теги блоков с одинаковым именем здесь используются для замены соответствующих блоков в base.html.
Снова перейдите по адресу http://127.0.0.1:8000/example, вывод следующий:
