Когда мы начали работать с шаблонами в Django, всё было довольно просто:
мы просто подставляли данные в шаблон через двойные фигурные скобки {{ }}.
Но настоящая сила шаблонов раскрывается тогда, когда мы начинаем управлять тем, что и как отображается на странице. Для этого Django предлагает теги шаблонов — особые конструкции, которые добавляют логику прямо внутрь HTML.
Сегодня мы познакомимся с самыми базовыми, но крайне важными тегами:
{% for %}— для циклов (перебора элементов);{% if %}— для условий;{% url %}— для формирования ссылок на основе маршрутов.
Представим, что у нас есть база фильмов (в будущем мы будем брать их из модели, но пока сделаем простую имитацию):
# views.py
from django.shortcuts import render
data_db = [
{'id': 1, 'title': 'Inception', 'description': 'Фильм о снах и реальности.', 'is_published': True},
{'id': 2, 'title': 'Tenet', 'description': 'Фильм, где время идёт в обратную сторону.', 'is_published': False},
{'id': 3, 'title': 'Interstellar', 'description': 'Фильм о космосе и времени.', 'is_published': True},
]
def index(request):
data = {
'title': 'Главная страница',
'menu': ['Главная', 'Фильмы', 'Контакты'],
'films': data_db,
}
return render(request, 'movies/index.html', context=data)Теперь создадим шаблон index.html:
<!DOCTYPE html>
<html lang="ru">
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>{{ title }}</h1>
<p>{{ menu|join:" | " }}</p>
<ul>
{% for film in films %}
<li>
<h2>{{ film.title }}</h2>
<p>{{ film.description }}</p>
<hr />
</li>
{% endfor %}
</ul>
</body>
</html>Теперь запусти сервер и открой страницу / в браузере.
Ты должен увидеть список фильмов с их описанием.
На странице отображаются все фильмы, включая те, у которых is_published=False.
Давайте скроем неопубликованные фильмы.
<ul>
{% for film in films %}
{% if film.is_published %}
<li>
<h2>{{ film.title }}</h2>
<p>{{ film.description }}</p>
{% if not forloop.last %}
<hr />
{% endif %}
</li>
{% endif %}
{% endfor %}
</ul>Теперь в браузере будут показаны только опубликованные фильмы (is_published=True).
Обрати внимание на переменную forloop.last.
Django предоставляет набор специальных переменных внутри цикла:
| Переменная | Значение |
|---|---|
forloop.counter |
Номер итерации, начиная с 1 |
forloop.counter0 |
Номер итерации, начиная с 0 |
forloop.first |
True, если это первая итерация |
forloop.last |
True, если это последняя итерация |
Попробуй использовать forloop.counter, чтобы пронумеровать фильмы:
<li>
<h2>{{ forloop.counter }}. {{ film.title }}</h2>
<p>{{ film.description }}</p>
</li>Теперь каждый фильм будет выводиться с номером.
До этого момента мы писали статические HTML-ссылки, например:
<a href="/film/1/">Подробнее</a>Но в реальном приложении маршруты могут меняться.
Чтобы не редактировать каждый шаблон вручную, Django предлагает тег {% url %}.
Добавим маршруты в urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='home'),
path('film/<int:film_id>/', views.show_film, name='film'),
]Добавим представление:
from django.http import HttpResponse
def show_film(request, film_id):
return HttpResponse(f"Отображение фильма с id = {film_id}")Теперь в шаблоне создадим динамическую ссылку на фильм:
<p><a href="{% url 'film' film.id %}">Подробнее</a></p>Если ты изменишь маршрут
film/<int:film_id>/вurls.py, Django сам подставит новое значение во все шаблоны, где используется тег{% url %}. Это делает проект гораздо более гибким и защищает от «битых ссылок».
Добавим меню в views.py:
# movies/views.py
menu = [
{'title': "О сайте", 'url_name': 'about'},
{'title': "Добавить фильм", 'url_name': 'add_film'},
{'title': "Контакты", 'url_name': 'contact'},
{'title': "Войти", 'url_name': 'login'}
]Добавим маршруты и заглушки:
# movies/urls.py
urlpatterns = [
path('', views.index, name='home'),
path('about/', views.about, name='about'),
path('add_film/', views.add_film, name='add_film'),
path('contact/', views.contact, name='contact'),
path('login/', views.login, name='login'),
path('film/<int:film_id>/', views.show_film, name='film'),
]# movies/views.py
def index(request):
data = {
'title': 'Главная страница',
'menu': menu, # Добавили меню
'films': data_db,
}
return render(request, 'movies/index.html', context=data)
...
def about(request):
return HttpResponse("О сайте CinemaHub")
def add_film(request):
return HttpResponse("Добавление фильма")
def contact(request):
return HttpResponse("Контакты")
def login(request):
return HttpResponse("Авторизация")Теперь в шаблоне выведем меню:
<ul>
<li><a href="{% url 'home' %}">Главная</a></li>
{% for m in menu %}
<li><a href="{% url m.url_name %}">{{ m.title }}</a></li>
{% endfor %}
</ul>Проверь страницу — теперь ссылки меню автоматически формируются по именам маршрутов.
Если ты изменишь путь в urls.py, шаблон сам подстроится.
-
Ошибка: "NoReverseMatch" Происходит, если имя маршрута указано неправильно или нет нужных аргументов. Проверь
urls.pyи убедись, что передаёшь все необходимые параметры. -
Ошибка внутри цикла
forDjango не поддерживает сложные выражения в шаблонах (например,film.id + 1). Если нужно обработать данные — делай это воviews.py, а не в шаблоне. -
Забыл закрыть тег Все теги в Django (например,
{% if %},{% for %}) требуют закрытия:{% endif %},{% endfor %}— без них шаблон не будет работать.
- Добавь в список
data_dbсвой любимый фильм с описанием. - Сделай, чтобы он отображался в списке только если
is_published=True. - Добавь динамическую ссылку «Подробнее» для каждого фильма.
- В меню добавь пункт «Главная» и сделай, чтобы он вел на главную страницу.
- Попробуй поменять маршруты в
urls.pyи убедись, что шаблон продолжает работать без изменений.
- Для чего нужен тег
{% for %}в шаблонах Django? - Что делает тег
{% if %}и как он используется? - Как избежать вывода неопубликованных фильмов на страницу?
- Зачем нужен тег
{% url %}? - Что произойдёт, если ты изменишь маршрут в
urls.py, но не используешь тег{% url %}в шаблоне? - Что делает переменная
forloop.counter? - Что произойдёт, если забыть закрыть тег
{% if %}? - Почему использование тега
{% url %}безопаснее, чем прописывать URL вручную? - Как можно исключить последнюю горизонтальную линию
<hr>в цикле? - Что означает ошибка
NoReverseMatch?