Теги шаблонов — это логика внутри HTML. В отличие от {{ переменная }}, которая только выводит значение, теги {% %} управляют потоком: ветвления, циклы, URL, подключение блоков.
{% if %} — условный вывод
{% if user.is_authenticated %}
<a href="{% url 'logout' %}">Выйти</a>
{% elif user.is_staff %}
<a href="/admin/">Панель администратора</a>
{% else %}
<a href="{% url 'login' %}">Войти</a>
{% endif %}
Поддерживаются операторы: ==, !=, <, >, and, or, not, in.
{% if posts and not page_obj.has_next %}
<p>Это последняя страница.</p>
{% endif %}
{% if post.status == "published" %}
<span class="badge bg-success">Опубликовано</span>
{% endif %}
{% for %} — цикл по спискам
{% for post in posts %}
<article>
<h2>{{ post.title }}</h2>
<p>{{ post.summary }}</p>
</article>
{% empty %}
<p>Статей пока нет.</p>
{% endfor %}
{% empty %} — выполняется, если список пустой. Аналог if not posts.
Переменные внутри цикла
Django автоматически предоставляет forloop внутри цикла:
{% for post in posts %}
<div class="{% if forloop.first %}mt-0{% else %}mt-4{% endif %}">
{{ forloop.counter }}. {{ post.title }}
{% if forloop.last %}<hr>{% endif %}
</div>
{% endfor %}
| Переменная | Значение |
|---|---|
forloop.counter |
Номер итерации (с 1) |
forloop.counter0 |
Номер итерации (с 0) |
forloop.first |
True на первой итерации |
forloop.last |
True на последней итерации |
{% url %} — генерация ссылок
Не хардкодьте пути — используйте имена URL:
<!-- urls.py: path('posts/<slug:slug>/', PostDetailView.as_view(), name='post-detail') -->
<a href="{% url 'post-detail' slug=post.slug %}">{{ post.title }}</a>
<a href="{% url 'post-list' %}">Все статьи</a>
<a href="{% url 'admin:index' %}">Администрирование</a>
При переименовании URL в urls.py все ссылки обновятся автоматически.
{% csrf_token %} — защита форм
Любая форма с методом POST обязана содержать этот тег:
<form method="post" action="{% url 'comment-create' post.pk %}">
{% csrf_token %}
<textarea name="text"></textarea>
<button type="submit">Отправить</button>
</form>
Без {% csrf_token %} Django вернёт ошибку 403. Тег вставляет скрытое поле с уникальным токеном сессии.
{% load static %} — подключение статики
{% load static %}
<link rel="stylesheet" href="{% static 'css/main.css' %}">
<script src="{% static 'js/main.js' %}"></script>
<img src="{% static 'images/logo.png' %}" alt="Логотип">
{% load static %} нужно писать один раз в начале файла (или после {% extends %}). Подробнее — в статье про статические файлы.
{% block %} и {% extends %} — наследование шаблонов
Базовый шаблон определяет блоки-заглушки:
{# base.html #}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}DevBlog{% endblock %}</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
Дочерний шаблон наследует и заполняет блоки:
{% extends 'base.html' %}
{% block title %}{{ post.title }} — DevBlog{% endblock %}
{% block content %}
<h1>{{ post.title }}</h1>
<div>{{ post.body }}</div>
{% endblock %}
Подробнее — в статье про наследование шаблонов.
Полный пример: шаблон списка постов DevBlog
{% extends 'base.html' %}
{% load static %}
{% block title %}Статьи — DevBlog{% endblock %}
{% block content %}
<div class="container py-4">
<h1>Все статьи</h1>
{% if posts %}
<div class="row g-4">
{% for post in posts %}
<div class="col-12 col-md-6 col-lg-4">
<div class="card h-100">
<div class="card-body">
<h5 class="card-title">
<a href="{% url 'post-detail' slug=post.slug %}">
{{ post.title }}
</a>
</h5>
<p class="card-text text-muted">{{ post.summary }}</p>
</div>
<div class="card-footer text-muted small">
{{ post.published_at }}
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="alert alert-info">
Статей пока нет. Возвращайтесь позже!
</div>
{% endif %}
</div>
{% endblock %}
💬 Комментарии (0)
Комментариев пока нет
Станьте первым, кто поделится мнением об этой статье!