Представления и шаблоны — Рендеринг списка статей
В этой главе вы научитесь использовать представления Django для получения данных из базы данных и вместе с шаблонами рендерить список карточек статей на главной странице блога.
Роль представлений (View)
Представления — это основной логический слой Django, отвечающий за:
- Приём пользовательских запросов (
requestпараметр) - Запрос необходимых данных из базы данных
- Передача данных в шаблоны для рендеринга HTML и возврат их пользователю.
Django-представления можно писать двумя способами:Функциональное представление (FBV)и представления на основе классов (CBV).
В первых восьми главах мы отдаём приоритет FBV (представления на основе функций) — они более интуитивны и подходят для начинающих, чтобы понять процесс обработки запросов.
Основы функциональных представлений
Функция представления Django получаетrequestПараметры и возвращаемые значенияHttpResponseОбъект.
Пример
from django.shortcuts import render
from .models import Post
def index(request):
"""Главная страница блога: отображает все статьи"""
# Запрос всех статей из базы данных (в обратном хронологическом порядке)
posts = Post.objects.all().order_by('-created_at')
# Три параметра render:
# 1. request — объект запроса
# 2. Путь к шаблону — blog/index.html
# 3. словарь context — данные, передаваемые в шаблон
context = {
'posts': posts,
'title': 'EXAMPLE Blog - Главная'
}
return render(request, 'blog/index.html', context)
render()Это наиболее часто используемая сокращённая функция в Django, объединяющая: загрузку шаблонов → внедрение данных → генерацию HTML → возврат ответов.
Синтаксис шаблонов Django
Синтаксис шаблонов Django очень похож на синтаксис шаблонов Vue3, но есть несколько ключевых различий.
| Назначение | Шаблоны Django | Шаблон Vue3 |
|---|---|---|
| Вывод переменных | {{ variable }} | {{ variable }} |
| Циклы | {% for item in list %}...{% endfor %} | v-for="item in list" |
| Условия | {% if cond %}...{% endif %} | v-if="cond" |
| Генерация URL | {% url 'name' %} | router-link to="name" |
| Наследование макета | {% extends 'base.html' %} | Вложенность компонентов |
Ключевое различие: шаблоны Django используют
{% %}Обёртывающие управляющие теги; Vue3 используетv-директивы. В шаблонах Django,серверныйрендеринг—HTML генерируется, а затем отправляется в браузер; Vue3 выполняетбраузерныйрендеринг—браузер получает JS, а затем собирает HTML.
Наследование шаблонов: base.html
Когда несколько страниц используют одну и ту же панель навигации и нижний колонтитул, используйтенаследование шаблонов.Избегайте дублирования.
Родительский шаблон определяет блоки, а дочерние шаблоны заполняют конкретным содержимым.
Создайте родительский шаблон base.html
Пример
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}EXAMPLE Blog{% endblock %}</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f5f5f5;
color: #333;
}
.navbar {
display: flex; justify-content: space-between; align-items: center;
padding: 16px 40px; background: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.navbar .logo { font-size: 22px; font-weight: bold; color: #2c3e50; text-decoration: none; }
.navbar a { margin-left: 20px; text-decoration: none; color: #333; }
.container { max-width: 960px; margin: 40px auto; padding: 0 20px; }
.footer { text-align: center; padding: 20px; color: #999; border-top: 1px solid #eee; }
.section-title { font-size: 24px; margin-bottom: 20px; }
</style>
{% block extra_head %}{% endblock %}
</head>
<body>
<!-- Панель навигации -->
<header class="navbar">
<a href="/" class="logo">ПРИМЕР Блог</a>
<nav>
<a href="/">Главная</a>
<a href="#">О нас</a>
</nav>
</header>
<!-- Основная область содержимого (заполняется дочерним шаблоном) -->
<main class="container">
{% block content %}
{% endblock %}
</main>
<!-- Подвал -->
<footer class="footer">
<p>© 2024 EXAMPLE Blog. Работает на Django.</p>
</footer>
</body>
</html>
Создайте дочерний шаблон index.html
Пример
<!-- extends должен быть в самом начале -->
{% extends 'blog/base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h2 class="section-title">Последние статьи</h2>
{% if posts %}
<div class="article-grid">
{% for post in posts %}
<div class="article-card">
<div class="card-content">
<span class="card-category">{{ post.category.name }}</span>
<h3>{{ post.title }}</h3>
<p>{{ post.summary|truncatechars:80 }}</p>
<span class="card-date">{{ post.created_at|date:"Y-m-d" }}</span>
</div>
</div>
{% endfor %}
</div>
{% else %}
<p class="empty-tip">Пока нет статей, пожалуйста, следите за обновлениями.</p>
{% endif %}
{% endblock %}
Несколько моментов, используемых в шаблонах:
| Синтаксис | Значение |
|---|---|
{% extends 'blog/base.html' %} | Наследование родительского шаблона должно быть записано в первой строке |
{% block content %}...{% endblock %} | Заполните блок содержимого, определённый в родительском шаблоне. |
{{ post.category.name }} | Доступ к свойствам связанных объектов через внешние ключи |
{{ post.summary|truncatechars:80 }} | Фильтр: обрезать до первых 80 символов |
{{ post.created_at|date:"Y-m-d" }} | Фильтр: форматировать дату |
В шаблонах Django,ФильтрИспользовать символ вертикальной черты
|Указывает, ставится после переменной, используется для форматированного вывода. Распространённые фильтры:date、truncatechars、length、default。
Добавление стилей к списку статей
Добавьте следующий CSS в тег style в base.html:
Пример
.article-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 24px;
}
.article-card {
background: #fff;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
transition: transform 0.2s, box-shadow 0.2s;
}
.article-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
.card-content {
padding: 20px;
}
.card-category {
display: inline-block;
padding: 2px 10px;
background: #E8EEF5;
color: #3D71A6;
border-radius: 12px;
font-size: 12px;
margin-bottom: 8px;
}
.article-card h3 {
font-size: 18px;
margin-bottom: 8px;
color: #222;
}
.article-card p {
font-size: 14px;
color: #666;
line-height: 1.6;
margin-bottom: 12px;
}
.card-date {
font-size: 12px;
color: #999;
}
.empty-tip {
text-align: center;
color: #999;
padding: 60px 0;
font-size: 16px;
}
Практика: проверьте, как выглядит главная страница
Убедитесь, что выполнены следующие пункты:
- Модели Post и Category определены в models.py и миграции выполнены
- В админ-панели добавлено как минимум 3–5 статей (отнесённых к разным категориям).
- Функция index в views.py запрашивает статьи из базы данных и передаёт их в шаблон.
- Маршрут / в urls.py указывает на представление index
Запустите сервер и откройте главную страницу. Вы должны увидеть список карточек статей, динамически отрисованных из данных базы данных.
Итоги главы
В этой главе вы освоили основное взаимодействие представлений и шаблонов Django: views.py запрашивает данные из базы данных и передаёт их в контекст, render() отрисовывает шаблоны, родительский шаблон base.html определяет макет и блоки, дочерние шаблоны расширяют его и заполняют содержимое, а также синтаксис шаблонов Django ({{ }}, {% %}, фильтры).
Главная страница блога теперь управляется базой данных, а не задана жёстко в коде.
Другие расширения