Шаблоны, начало. Функции render() и render to string()

Курс по Django: https://stepik.org/a/183363

Архив проекта: 09_sitewomen.zip

На этом занятии мы с вами познакомимся со второй компонентой паттерна проектирования MTV – шаблонами (templates). Что это такое? Вот смотрите, если мы откроем наш проект и запустим тестовый веб-сервер, то на главной странице увидим отображение одной короткой строчки. Как вы понимаете, полноценная HTML-страница содержит гораздо больше информации, в том числе, заголовок и подключаемые статические файлы. Конечно, если решать эту задачу «в лоб», то можно было бы написать в функции представления что-то вроде:

def index(request):
    return HttpResponse('''<!DOCTYPE html>
<html>
<head>
         <title></title>
</head>
<body>
 
</body>
</html>''')

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

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

https://www.youtube.com/watch?v=cFJqMXxVNsI&list=PLA0M1Bcd0w8wfmtElObQrBbZjY6XeA06U

Далее, я буду полагать, что вы владеете этим материалом. Если это не так, то рекомендую с ним ознакомиться, прежде чем двигаться дальше. Также рекомендую посмотреть документацию по шаблонам Django:

https://docs.djangoproject.com/en/4.2/topics/templates/

Итак, предположим, что в качестве главной страницы мы бы хотели отобразить некоторый шаблон с именем index.html. Для этого, вначале нам нужно импортировать функции, через которые запускается встроенный в Django шаблонизатор. В самом простом варианте можно использовать функцию:

from django.template.loader import render_to_string

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

def index(request):
    t = render_to_string('путь к шаблону index.html')
    return HttpResponse(t)

И здесь мы подошли ко второму важному вопросу: где должны располагаться шаблоны текущего приложения Women? По умолчанию, Django ищет шаблоны в подкаталоге templates нашего приложения. Создадим его. По идее, мы можем располагать здесь наши файлы шаблонов и все должно работать. Но есть один важный нюанс. В каком-либо другом приложении также может оказаться файл с именем index.html. Тогда фреймворк Django будет использовать тот, что встретится первым. Чтобы этого не происходило, в templates приложения принято создавать еще один подкаталог с именем приложения. В нашем случае – women. И уже в него помещать файлы шаблонов. Тогда все наши файлы шаблонов будут отделяться от других дополнительным подкаталогом и это позволит избежать коллизий имен файлов.

Итак, создадим в подкаталоге templates/women файл index.html с содержимым:

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>Главная страница</title>
</head>
<body>
<h1>Главная страница</h1>
</body>
</html>

Это будет наш первый простейший шаблон, представляющий главную страницу сайта. И, далее, в функции render укажем путь к этому шаблону:

def index(request):
    t = render_to_string('women/index.html')
    return HttpResponse(t)

Все, при обновлении главной страницы в браузере, мы увидим этот шаблон. Как видите все достаточно просто и удобно. Но можно сделать еще лучше и воспользоваться функцией:

from django.shortcuts import render

которая объединяет в себе рендер шаблона и формирование ответа сервера. В результате функция представления index() может быть записана так:

def index(request):
    return render(request, 'women/index.html')

Обратите внимание, для корректного отображения кириллицы все шаблоны рекомендуется сохранять в кодировке utf-8. Тем более что сам Python, начиная с версии 3, по умолчанию использует юникод.

Давайте для примера добавим еще одну страницу и один шаблон на наш сайт – страницу «О сайте». Пропишем следующие пути (в women/urls.py):

urlpatterns = [
    path('', views.index, name='home'),
    path('about/', views.about, name='about'),]

И функцию about в файле women/views.py:

def about(request):
    return render(request, 'women/about.html')

Добавим шаблон about.html:

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>О сайте</title>
</head>
<body>
<h1>О сайте</h1>
</body>
</html>

И при переходе по адресу:

http://127.0.0.1:8000/about/

этот шаблон будет отображен.

Настройки шаблонизатора

При работе функций render_to_string() и render() фреймворк Django использует шаблонизатор, указанный в параметре TEMPLATES файла settings.py пакета конфигурации. В частности мы там видим строчку:

'BACKEND': 'django.template.backends.django.DjangoTemplates',

означающую, что используется встроенный шаблонизатор Django. Кроме того здесь есть параметры DIRS и APP_DIRS. Параметр DIRS позволяет прописывать нестандартные пути к файлам шаблонов, а APP_DIRS со значением True указывает шаблонизатору Django искать шаблоны также и внутри приложений. Причем, шаблоны сначала ищутся по коллекции DIRS, а затем уже в приложениях. В частности, благодаря этому параметру успешно обнаруживаются наши шаблоны index.html и about.html внутри приложения women. Если установить параметр APP_DIRS в значение False, то при запуске проекта и перехода на главную страницу:

http://127.0.0.1:8000

появится ошибка:

TemplateDoesNotExist at /

говорящая, что шаблон не был найден. Возвращая значение параметра APP_DIRS в True ошибка пропадает.

Обратите внимание, чтобы шаблоны нашего приложения успешно обнаруживались фреймворком Django, приложение должно быть прописано в коллекции INSTALLED_APPS. Если мы его оттуда уберем, то снова возникнет прежняя ошибка. Кстати, ради интереса мы можем ее исправить, добавив абсолютный путь в коллекцию DIRS параметра TEMPLATES. Сделать это можно следующим образом:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            BASE_DIR / 'women' / 'templates'
        ],
        'APP_DIRS': True,
    ...
    },
]

Мы здесь воспользовались переменной BASE_DIR, которая хранит абсолютный путь к нашему проекту, и добавили подкаталоги women и templates к файлам шаблонов нашего приложения. Теперь, фреймворк Django без проблем найдет нужные файлы и отобразит на главной странице.

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

Курс по Django: https://stepik.org/a/183363

Видео по теме