Создание тегов шаблонизатора Django
Джанго предоставляет следующие вспомогательные функции, позволяющие создавать собственные теги шаблонов простым способом:
- simple_tag: обрабатывает данные и возвращает строку
- inclusion_tag: обрабатывает данные и возвращает обработанный шаблон
- assignment_tag: обрабатывает данные и задает переменную в контексте
Теги шаблонов должны жить внутри приложений Джанго.
В каталоге приложения блога создайте новый каталог, назовите его templatetags и добавьте в него пустой файл __init__.py Создайте еще один файл в той же папке и назовите его blog_tags.py. Фаловая структура приложения блога должна выглядеть следующим образом:
blog/
__init__.py
models.py
...
templatetags/
__init__.py
blog_tags.py
Имя файла имеет важное значение. Имя этого модуля будет использоваться для загрузки тегов в шаблоны.
Начнем с создания простого тега, чтобы получить общее количество записей, опубликованных в блоге. Отредактируйте только что созданный файл blog_tags.py и добавьте следующий код:
from django import template
register = template.Library()
from ..models import Post
@register.simple_tag
def total_posts():
return Post.published.count()
Создан простой тег шаблона, который возвращает количество опубликованных записей. Каждый модуль тегов шаблона должен содержать переменную, называемую register, в качестве допустимой библиотеки тегов. Эта переменная является экземпляром шаблона. Библиотека и используется для регистрации собственных тегов шаблонов и фильтров. Затем мы определим тег с именем total_posts с функцией Python и с помощью функции @register.simple_tag, чтобы определить функцию как простой тег и зарегистрировать ее. Джанго будет использовать имя функции в качестве имени тега. Если требуется зарегистрировать его с другим именем, это можно сделать, указав атрибут name, например @register.simple_tag(name='my_tag').
После добавления нового модуля тегов шаблонов необходимо перезапустить сервер разработки Джанго, чтобы использовать новые теги и фильтры шаблонов.
Перед использованием пользовательских тегов шаблонизатора необходимо сделать их доступными для шаблона с помощью тега {% load %}
. Как упоминалось ранее, необходимо использовать имя модуля Python, содержащего теги шаблонов и фильтры. Откройте шаблон blog/base.html и добавьте в его верхнюю часть {% load blog_tags %}
, чтобы загрузить модуль тегов шаблонов. Затем используйте созданный тег для отображения количества записей. Просто добавьте в шаблон {% total_posts %}
. Шаблон должен выглядеть следующим образом:
{% load blog_tags %}
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock %}</title>
<link href="{% static "css/blog.css" %}" rel="stylesheet">
</head>
<body>
<div id="content">
{% block content %}
{% endblock %}
</div>
<div id="sidebar">
<h2>My blog</h2>
<p>This is my blog. I've written {% total_posts %} posts so far.</p>
</div>
</body>
</html>
Для отслеживания новых файлов, добавленных в проект, необходимо перезагрузить сервер. Остановите сервер разработки с помощью комбинаций клавиш Ctrl+C и запустите его снова, используя эту команду:
python manage.py runserver
Откройте http://127.0.0.1:8000/blog/ в своем браузере. Вы должны увидеть общее количество постов в сайдбаре:
Мощь пользовательских тегов шаблонов заключается в том, что можно обрабатывать любые данные и добавлять их в любой шаблон независимо от выполняемого представления. Можно выполнять QuerySets или обрабатывать любые данные для отображения результатов в шаблонах.
Теперь создадим еще один тег для отображения последних сообщений в боковой панели нашего блога. На этот раз мы будем использовать inclusion_tag. С помощью inclusion_tag можно визуализировать шаблон с переменными контекста, возвращаемыми тегом шаблона. Добавьте следующий код в файл blog_tags.py:
@register.inclusion_tag('blog/post/latest_posts.html')
def show_latest_posts(count=5):
latest_posts = Post.published.order_by('-publish')[:count]
return {'latest_posts': latest_posts}
В этом коде мы регистрируем тег шаблона с помощью @register.inclusion_tag, и мы указываем шаблон, который должен быть визуализирован с возвращаемыми значениями в blog/post/latest_posts.html. Тег шаблона будет принимать необязательный параметр count, который по умолчанию имеет значение 5, и позволяет указать количество комментариев, которые требуется отобразить. Эта переменная используется для ограничения результатов запроса Post.published.order_by('-publish')[:count]. Обратите внимание, что функция возвращает словарь вместо простого значения. inclusion_tag должен возвращать словарь значений, используемый в качестве контекста для визуализации указанного шаблона. Теги включения возвращают словарь. Тег шаблона, который мы только что создали, можно использовать для передачи числа комментариев, которые будут отображаться как {% show_latest_posts 3 %}
Теперь создайте файл latest_posts.html в директории blog/post/ и добавьте в него следующий код:
<ul>
{% for post in latest_posts %}
<li>
<a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
Здесь отображается неупорядоченный список записей с использованием переменной latest_posts, возвращаемой нашим тегом шаблона. Теперь отредактируйте шаблон blog/base.html и добавьте новый тег шаблона для отображения последних 3 комментариев. Блок боковой панели должен выглядеть следующим образом:
<div id="sidebar">
<h2>My blog</h2>
<p>This is my blog. I've written {% total_posts %} posts so far.</p>
<h3>Latest posts</h3>
{% show_latest_posts 3 %}
</div>
Тег шаблона вызывается для отображения числа комментариев, а шаблон отображается на месте с заданным контекстом.
Теперь вернитесь в браузер и обновите страницу. Боковая панель должна выглядеть следующим образом:
Наконец, мы собираемся создать assignment_tag. Теги присваивания похожи на простые теги, но они сохраняют результат в заданной переменной. Мы создадим assignment_tag для отображения записей с комментариями. Измените файл blog_tags.py:
from django.db.models import Count
@register.assignment_tag
def get_most_commented_posts(count=5):
return Post.published.annotate(total_comments=Count('comments')).order_by('-total_comments')[:count]
Этот запрос использует функцию annotate() для агрегирования запросов с помощью статистической функции count. Мы строим запрос, получающий общее количество комментариев для каждой записи в поле total_comments, и сортируем их с помощью функции order_by(). Кроме того, для ограничения общего числа объектов, возвращаемых к заданному значению, также предоставляется необязательная переменная count.
В adition to Count, Джанго предлагает статистические функции Avg , Max , Min , и Sum. Дополнительные сведения об агрегатных функциях можно прочитать здесь: https://docs.djangoproject.com/en/1.8/topics/db/aggregation/
Отредактируйте шаблон blog/base.html и добавьте следующий код к боковой панели:
<h3>Most commented posts</h3>
{% get_most_commented_posts as most_commented_posts %}
<ul>
{% for post in most_commented_posts %}
<li>
<a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
Нотацией для тегов шаблона назначения является {% template_tag as variable %}
. Для тега шаблона мы используем {% get_most_commented_posts as most_commented_posts %}
. Таким образом, мы сохраняем результат тега шаблона в новой переменной с именем most_commented_posts. Затем отображаются возвращенные сообщения в виде неупорядоченного списка.
Теперь откройте браузер и обновите страницу, чтобы увидеть конечный результат. Он должен выглядеть следующим образом:
Вы можете узнать больше про создание пользовательских тегов шаблонизатора https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/