Теория
Templates — шаблоны, один из основных составляющих в идеологии MTV, на котором построена обработка и выдача данных в Django.
Шаблоны(Tеmplates) от видов в Django отличаются тем, что первые представляют из себя куски страниц HTML, которые соединяют методом наследования в одно целое, а процесс их выдачи и обработки происходит в Видах(Views).
Шаблоны имеют иерархию наследования от общего к частному. Это необходимо, чтобы код верстки не повторялся на страницах в пределах проекта, поэтому, есть базовый код шаблона, который наследуется всеми страницами проекта и есть частный код, который задается локально для каждого приложения.
Практика
Шаблоны хранятся в папке templates внутри каждого проекта, это стандарт Django и Django будет всегда, первым делом, искать шаблоны в этой папке. Есть папка templates в пределах приложения и есть корневая папка templates, которая содержит одинаковый для всех приложений код HTML и выглядит эта иерархия, как внизу
[myproject]/ ├── [myproject]/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── [blog]/ │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── moddels.py │ ├── views.py │ ├── urls.py │ ├── templates/ │ │ └──blog/ │ │ ├──base_blog.html │ │ └──index.html │ └── tests.py ├── templates/ │ └──base.html └── manage.py
Создадим эти папки, как указано в иерархии с их содержимыми. Отдельно остановимся на содержимых этих папок.
Содержимое папки templates/:
- blog/ — одноименная папка для интимных шаблонов приложения;
- index.html — индексная страница вывода обработки данных приложения;
- base_blog.html — базовый шаблон в пределах приложения, который наследует base.html и от которого наследуются остальные страницы в пределах приложения.
Содержимое папки blog/templates/:
- base.html — базовый шаблон для всех страницы в пределах проекта.
Примечание. Важно учитывать, что процесс наследования не обязателен, но, как принято, что нельзя повторять однотипный код для одинаковых частей страниц, к примеру для меню, хедера, футера, боковых частей и т.п., так как это будет усложнять отладку и производительность работы над проектом упадет.
Теперь, давайте, все по порядку будем редактировать и разъяснять куски кода.
Открываем файл blog/views.py и через функцию рендера подключаем шаблон index.html
from django.shortcuts import render #from django.http import HttpResponse # Create your views here. def posts_list(request): posts = ['post 1', 'post 2', 'post 3', 'post 4', 'post 5',] return render(request, 'blog/index.html', context = {'posts' : posts}) #return HttpResponse("<h1>Hello! Hello!</h1>")
Функция render(…) выводит шаблон вторым параметром, первым параметром она принимает данные запроса, а третьим — контекст с данными из вида в шаблон. Третий параметр этой функции является связующим звеном между Видом(View) и Шаблоном(Template), точнее сказать, отправляет в шаблон данные на вывод и в данном случае, для примера, передадим из вида в шаблон список постов в виде массива.
Открываем файл корневого шаблона templates/base.html и ставим такой код
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> {% block title %} Page title {% endblock %} </title> <script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script> <!-- Compressed CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/foundation-sites@6.5.0/dist/css/foundation.min.css" integrity="sha256-VEEaOnBKVRoYPn4AID/tY/XKVxKEqXstoo/xZ6nemak= sha384-D46t32f421/hB30qwnim2pIcisNN5GU9+6m2Mfnd3dKpTSFidZLa08/1StEiCFId sha512-WkgzH8VKemDfwrp18r+wgbx+oHXOkfd2kJs7ocAXdGDgonXDXh88E90IRtRZRXtO0IHprxYHYlY14h+wyTsUDA==" crossorigin="anonymous"> <!-- Compressed JavaScript --> <script src="https://cdn.jsdelivr.net/npm/foundation-sites@6.5.0/dist/js/foundation.min.js" integrity="sha256-GZq6aeugpWo25iH//1eKmeK6FHCf+6KXTfoUpkCqPCA= sha384-vjxUQtbGw5FJMigaaFpXYyxoHHLb7LbvRywnMZOiPJeh5j9sl2rnmQ3iucuegRm8 sha512-h7tIMIX/opZXfWkcTDbkO+nT0LePyAAwDacfYhWtgGUidV+Kkh3eesW52fPSxKEsw3rgywKhQvghNLT4eDuUyw==" crossorigin="anonymous"></script> </head> <body> <nav class="main-navigation"> <div class="title-bar" data-responsive-toggle="example-menu" data-hide-for="medium"> <button class="menu-icon" type="button" data-toggle="example-menu"></button> <div class="title-bar-title">Menu</div> </div> <div class="top-bar" id="example-menu"> <div class="top-bar-left"> <ul class="dropdown menu" data-dropdown-menu> <li class="menu-text">Site Title</li> <li> <a href="#">One</a> <ul class="menu vertical"> <li><a href="#">One</a></li> <li><a href="#">Two</a></li> <li><a href="#">Three</a></li> </ul> </li> <li><a href="#">Two</a></li> <li><a href="#">Three</a></li> </ul> </div> <div class="top-bar-right"> <ul class="menu"> <li><input type="search" placeholder="Search"></li> <li><button type="button" class="button">Search</button></li> </ul> </div> </div> </nav> {% block content %} Page content {% endblock %} <script> $(document).foundation(); </script> </body> </html>
В данном файле есть несколько моментов, которые следует упомянуть:
- блоки для шаблонов кода, которые начинаются с ключевого слова block и заканчиваются ключевым словом endblock. Данные блоки играют роль вешалки на странице, в последующем, в частных страницах приложений эти места можно заменять индивидуальным содержимым, а вот ключевое слово extends указывает файл шаблона, от которого будет происходить наследование;
- мы подключили фронтенд фреймворк Zurb Foundation, который сделает элементы на странице чуть более привлекательным, а сетку более понятной и структурированной. Последние ссылки на CDN можно найти тут. К теме разработки на Django это не относится, мы могли бы вместо него включить и Bootstrap, но я предпочел первое.
Открываем частный шаблон blog/templates/wp_base.html и вставляем такой код и сохраняем
{% extends 'base.html' %}
Открываем частный шаблон blog/templates/blog/index.html и вставляем такой код и сохраняем
{% extends 'blog/base_blog.html'%} {% block title %} Blog page {% endblock %} {% block content %} <div> <div class="grid-x"> {% for post in posts %} <div class="cell small-12 medium-3 large-3"> <div class="card"> <img src="https://foundation.zurb.com/sites/docs/assets/img/generic/rectangle-1.jpg"> <div class="card-section"> <h4>{{ post }}</h4> <p>This row of cards is embedded in.</p> </div> </div> </div> {% endfor %} </div> </div> {% endblock %}
Как вы помните,файл blog/templates/blog/index.html мы подключали к нашему виду blog/views.py из которого передавали через контекст массив постов posts. Данные массив выводится при помощи цикла в этом шаблоне. Особ следует отметить, что мы наследуем данный шаблон от базового шаблона blog/templates/blog/base_blog.html, являющийся корневым в пределах текущего приложения и который, в свою очередь, наследуется от корневого templates/blog/base.html в пределах всего проекта.
Примечание. В шаблонах используются 2 вида скобок шаблонизации:
- {% [выражение pyhton] %} — в таких скобках вычисляются выражения;
- {{ [переменная на вывод] }} — в таких скобках значение переменной выводят на показ в шаблон.
После всего выше перечисленого остался один момент, связанный с нахождением корневого шаблона проекта, его надо явно указать в файле settings.py, иначе файл blog/templates/blog/wp_base.html не сможет найти и унаследовать его. Для этого нужно открыть файл settings.py и добавить абсолютный путь к папке корневого шаблона проекта
... TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], ... ...
После окончания работы перезапускаем сервер и мы должны увидеть вот такой результат