Django предлагает множество встроенных тегов, таких как {% if %}
или {% block %}
. Некоторые из них были использованы в ранее рассмотренных шаблонах. С полным списком можно ознакомиться по ссылке: https://docs.djangoproject.com/en/2.0/ref/templates/builtins/.
Тем не менее Django дает возможность создавать собственные шаблонные теги для осуществления любых действий. Они пригодятся в тех случаях, когда требуемая функциональность не найдется среди базового набора Django.
Создание тега
Django предлагает следующие вспомогательные функции, которые позволят с легкостью создавать собственные шаблонные теги:
simple_tag
: обрабатывает данные и возвращает строку.inclusion_tag
: обрабатывает данные и возвращает отрисованный шаблон.
Шаблонные теги могут использоваться только внутри приложений Django.
В папке приложения blog
создайте новую папку, назовите ее templatetags
и добавьте пустой файл __init__.py
. Создайте еще один файл blog_tags.py
. Файловая структура приложения блога должна быть следующей:
blog/
__init__.py
models.py
...
templatetags/
__init__.py
blog_tags.py
Важно выбирать правильные названия, поскольку они будут использоваться для загрузки тегов в шаблонах.
Начнем с создания простого тега, который будет получать общее количество опубликованных в блоге постов. Отредактируйте файл blog_tags.py
и добавьте следующий код:
from django import template
from ..models import Post
register = template.Library()
@register.simple_tag
def total_posts():
return Post.published.count()
Этот тег возвращает количество опубликованных постов. Каждый модуль с шаблонными тегами, чтобы являться действительной библиотекой тегов, должен включать переменную register
. Эта переменная — экземпляр template.Library
. Она используется для регистрации собственных шаблонных тегов и фильтров. Дальше нужно определить тег total_posts
с помощью функции Python и использовать декоратор @register.simple_tag
для регистрации его в качестве простого тега. Django использует имя функции в качестве имени тега. Если хочется выбрать другое имя, это можно сделать с помощью атрибута name
, например, @register.simple_tag(name='my_tag')
.
После добавления нового модуля шаблонных тегов нужно перезагрузить сервер разработки Django, чтобы изменения вступили в силу, а новые теги и фильтры можно было использовать.
Перед тем как начинать использовать собственные шаблонные теги, их нужно сделать доступными с помощью тега {% load %}
. Как упоминалось ранее, необходимо использовать имя модуля Python, включающего шаблонные теги и фильтры. Откройте шаблон и добавьте сверху {% load blog_tags %}
для загрузки модуля тегов шаблона. Затем используйте созданный тег для отображения общего количества опубликованных постов. Просто добавьте тег {% total_posts %}
в шаблон. Он будет выглядеть вот так:
{% load blog_tags %}
{% load static %}
<!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
Откройте https://127.0.0.1:8000/blog/ в браузере. Отобразится общее количество опубликованных постов:
Преимущество собственных тегов в том, что с их помощью можно обрабатывать любые данные и добавлять в любой шаблон вне зависимости от представления. Можно использовать QuerySet или обрабатывать любые данные для отображения результатов в шаблонах.
Теперь создадим еще один тег для отображения последних постов в сайдбаре. Будем использовать тег inclusion (включения). С его помощью можно рендерить шаблон с контекстными переменными, которые шаблонный тег возвращает. Отредактируйте файл 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]
. Обратите внимание, что функция возвращает словарь, а не одно значение. Включенный тег должен возвращать словарь значений, который используется как контекст для рендеринга определенного шаблона. Созданный тег шаблона позволяет определять количество постов для отображения по желанию: {% show_latest_posts 3 %}
.
Теперь нужно создать новый файл шаблона в папке blog/post/
и назвать его latest_posts.html
. Добавьте туда следующий код:
<ul>
{% for post in latest_posts %}
<li>
<a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
Этот код отображает неупорядоченный список постов с помощью переменной latest_posts
, которую возвращает тег шаблона. Теперь нужно отредактировать шаблон blog/base.html
и добавить в него тег шаблона для отображения последних трех постов. Код сайдбара должен выглядеть следующим образом:
<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>
Тег шаблона вызывается, передавая количество постов для отображения, а шаблон отрисовывается в нужной позиции с указанным контекстом.
Вернитесь в браузер и обновите странице. Сайдбар будет выглядеть так:
Наконец, создадим просто тег шаблона, который сохраняет результат в переменной так, чтобы его можно было использовать в дальнейшем. Создадим тег для отображения наиболее комментируемых постов. Отредактируйте файл blog_tags.py
и добавьте следующий импорт и шаблонный тег:
from django.db.models import Count
# ...
@register.simple_tag
def get_most_commented_posts(count=5):
return Post.published.annotate(
total_comments=Count('comments')
).order_by('-total_comments')[:count]
В нем с помощью функции annotate()
создаем QuerySet, который агрегирует общее количество комментариев под постов. Сейчас используются функция агрегации Count
для сохранения количества комментариев и поле total_comments
каждого объекта Post
. Отсортируем QuerySet по значению этого поля в убывающем порядке. Используем переменную count
для ограничения общего количество возвращаемых объектов.
В дополнение к Count
в Django есть такие функции агрегации, как Avg
, Max
, Min
и Sum
. О них можно почитать здесь https://docs.djangoproject.com/en/2.0/topics/db/aggregation/.
Отредактируйте шаблон blog/base.html
и добавьте следующий код к элементу сайдбара <div>
(после {% show_latest_posts 3 %}
):
<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>
Сохраним результат в переменной с помощью аргумента as
и имени переменной. Для тега шаблона используем {% get_most_commented_posts as most_commented_posts %}
для сохранения результата шаблонного тега в новой переменной most_commented_posts
. Затем отобразим посты в виде неотсортированного списка.
Откройте браузер и перезагрузите страницу, чтобы увидеть финальный результат:
Теперь вы знаете, как самостоятельно создавать шаблонные теги. Подробно о них можно почитать здесь https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/.