Зарегистрируйтесь, чтобы продолжить обучение

Шаблонизация Python: Разработка на фреймворке Django

Веб-приложение состоит из веб-страниц. Даже если приложение реализует большую часть интерфейса пользователя с помощью JavaScript, домашняя страница все равно отдается сервером. Да и ситуации, когда страничный сайт хорошо решает поставленные задачи, возникают часто. Поэтому подсистема шаблонизации остается важной частью full-stack фреймворков.

В этом уроке разберем, что такое шаблонизация, и как на ее основе Django формирует HTML-страницы.

Язык шаблонизации

Шаблон — это почти готовый текстовый документ, в котором все неизменные части текста представлены как есть. А изменяемая часть описана на некотором языке с ветвлениями, условиями и циклами. Они позволяют преобразовать данные в подходящее представление. Этот язык называют языком шаблонизации или templating language.

На уровне шаблона разделяется ответственность. Шаблон страницы знает, как отобразить данные в виде HTML. А сами данные не зависят от этого представления и могут быть представлены по-разному разными шаблонами. По данным вообще нельзя сказать, что они будут представлены в виде HTML. Шаблонизатор возводит барьер абстракции.

Чтобы из кода, который формирует данные, не нужно было программировать отображение, у шаблонизатора есть свой язык программирования отображения. А для того, чтобы не было соблазна прямо в шаблоне получать данные, этот язык сделан с ограниченными возможностями.

Шаблонизация в Django

В Django шаблонизация проработана достаточно глубоко. Есть встроенный шаблонизатор, можно использовать сторонние шаблонизаторы вроде Jinja2 и можно сочетать несколько шаблонизаторов в одном проекте. Это удобно, когда некоторые шаблоны достаются в наследство, либо когда мы переезжаем с одного шаблонизатора на другой.

Чтобы шаблон превратить в результат, Django использует бэкенды. Встроенных бэкенда два: DjangoTemplates и Jinja2. Сторонние пакеты могут предоставлять свои бэкенды.

Чтобы бэкенд мог что-то сделать с шаблоном, нужно этот шаблон где-то взять. Django самостоятельно загружает шаблоны из файлов, знает, где эти файлы найти, и запоминает/кэширует часто используемые шаблоны в памяти. Нам остается только помнить имя шаблона, который хотим использовать в данный момент.

Настраивается это в settings.py с помощью переменной TEMPLATES. Выглядит настройка так:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': False,
        'OPTIONS': {
            # ... параметры шаблонизатора ...
        },
    },
]
  • DIRS — параметр, который перечисляет директории, где будет производиться поиск шаблонов
  • APP_DIRS — параметр, который разрешает Django искать шаблоны в директориях приложений

Когда APP_DIRS включен, в каждом подключенном приложении будут по умолчанию искаться директории templates, а в них — шаблоны.

По умолчанию в качестве директории с шаблонами принято указывать templates:

# hexlet_django_blog/settings.py
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            # ... параметры шаблонизатора ...
    },
]

Шаблоны приложений

У одного приложения в нашем учебном проекте уже есть шаблон. Речь идет о главном приложении hexlet_django_blog и шаблоне hexlet_django_blog/templates/index.html. Django находит и загружает этот шаблон, потому что опция APP_DIRS включена по умолчанию.

Если сейчас создать новый шаблон hexlet_django_blog/article/templates/index.html, то при поиске по имени index.html первым будет найден старый шаблон hexlet_django_blog/templates/index.html. Так происходит, потому что приложение hexlet_django_blog находится в списке settings.INSTALLED_APPS выше приложения hexlet_django_blog.article. Если переставить приложения местами, то загрузчик шаблонов учтет изменения.

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

Чтобы не думать слишком много над тем, как не путать шаблоны, стоит придерживаться правила:

Все шаблоны проекта, которые используются только в нем, стоит хранить в отдельной директории в корне проекта и держать эту директорию в порядке — использовать поддиректории и хорошие имена. Директорию нужно добавить в settings.TEMPLATES.DIRS.

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

Контекст шаблонизации

Шаблоны превращаются в текст с помощью выполнения кода на языке шаблонизатора. Этот код обычно подразумевает использование каких-то данных, получаемых вне шаблона. Данные передаются в шаблон с помощью контекста, который представляет собой словарь. Когда мы вызываем render(request, 'template.html', context={}), мы передаем этот самый словарь в качестве аргумента.

Часто возникает задача иметь в контексте шаблона доступ к параметрам запроса или настройкам проекта. Передавать такие вещи явно слишком утомительно, поэтому у Django есть механизм Context Processors — посредники между нами и шаблоном, которые расширяют контекст единым образом для всех шаблонов.

Процессоры контекста вызываются как функции, которые получают в качестве аргумента request и возвращают словарь. Затем этот словарь дополняет предоставленный нами контекст. Подключаются context processors в settings.TEMPLATES.OPTIONS.context_processors — это список строк с полными именами процессоров.

С Django поставляется много готовых процессоров контекста. Вот два примера:

  • django.template.context_processors.request добавляет в контекст переменную request с очевидным значением
  • django.template.context_processors.debug добавляет переменную debug, которая истинна, если сервер запущен в режиме разработчика. С помощью этой переменной можно выводить какую-то отладочную информацию, которая не будет видна в боевом режиме

В дополнение к встроенным можно создавать и свои процессоры контекста или же брать их из сторонних библиотек.

Работа с шаблонизатором Django

Пример простого Django-шаблона:

<h1>{{ title }}</h1>
<p>{{ description }}</p>
<pre>
    {{ code }}
</pre>
<p>Question submitted at: {{ created_at }}</p>

Шаблон выглядит как HTML, но со вставками кода. Во многом встроенный Django шаблонизатор схож с шаблонизатором Jinja2 — подстановка любого значения выполняется в двойных фигурных скобках {{ ... }}. Это очень похоже на интерполяцию, если сам шаблон рассматривать как строку.

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

Данные в шаблон поступают из вью в виде контекста:

# hexlet_django_blog/views.py

def about(request):
    tags = ['обучение', 'программирование', 'python', 'oop']
    return render(
        request,
        'about.html',
        context={'tags': tags},
    )
<!-- hexlet_django_blog/templates/about.html -->

<h1>О блоге</h1>
<p>Эксперименты с Django на Хекслете</p>
<p>{{ tags|join:', ' }}</p>

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

Кроме подстановки во встроенном шаблонизаторе есть инструкции. С их помощью реализованы все управляющие конструкции, например, циклы, условия и многое другое:

{% if records|length == 1 %}
I have one record!
{% endif %}

{% for user in users %}
<p>This is user {{ user.id }}</p>
{% endfor %}

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

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


Самостоятельная работа

  1. Добавьте для hexlet_django_blog.article.views.index отдельный шаблон, который поместите в приложении hexlet_django_blog.article в директорию templates/articles
  2. Выводите название приложения с помощью шаблона. Используйте подстановки, все значения передавайте через контекст

Дополнительные материалы

  1. Django Templates
  2. Django tags and filters

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
Программирование на Python, Разработка веб-приложений и сервисов используя Django, проектирование и реализация REST API
10 месяцев
с нуля
Старт 26 декабря

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»