Шаблоны и наследование шаблонов в Django

👁 187 просмотров
1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (Пока оценок нет)
Загрузка...

Теория

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/blog_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/blog_base.html не сможет найти и унаследовать его. Для этого нужно открыть файл settings.py и добавить абсолютный путь к папке корневого шаблона проекта

...
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        ...
...

После окончания работы перезапускаем сервер и мы должны увидеть вот такой результат

Результат работы из ткущей статьи
Результат работы из ткущей статьи