Функциональность форм и избранного
В этой главе вы научитесь обрабатывать POST-запросы пользователей, устанавливать связи «многие ко многим» и реализовывать функцию «избранных статей».
Проектирование модели данных для функции избранного
Суть функции избранного:Пользователь может добавить в избранное несколько публикаций, и публикация может быть добавлена в избранное несколькими пользователями.。
Это типичная связь «многие ко многим» (ManyToMany).
Нам не нужно создавать новую модель — модель User в Django встроена; нам просто нужно добавить ManyToManyField, указывающий на User, в модель Post.
Пример
from django.contrib.auth.models import Пользователь
class Post(models.Model):
# ... существующие поля
# Коллекционер: ManyToManyField автоматически создаёт промежуточную таблицу
favorites = models.ManyToManyField(
Пользователь,
related_name='favorite_posts', # Обратный запрос: user.favorite_posts.all()
verbose_name='collector',
blank=True
)
После изменения модели сгенерируйте и выполните миграцию:
(venv) $ python manage.py makemigrations (venv) $ python manage.py migrate
Логика представления для добавления в избранное и удаления из избранного
Пример
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from .models import Post
# Декоратор login_required: когда неаутентифицированный пользователь обращается к этому представлению, автоматически перенаправляет на страницу входа
@login_required
def toggle_favorite(request, pk):
"""Переключить статус избранного: в избранном → убрать из избранного, не в избранном → добавить в избранное"""
post = get_object_or_404(Post, pk=pk)
# Проверить, добавил ли текущий пользователь в избранное
if post.favorites.filter(id=request.user.id).exists():
# В избранном → Убрать из избранного
post.favorites.remove(request.user)
messages.info(request, f'Убрано из избранного "{post.title}"')
else:
# Не в избранном → Добавить в избранное
post.favorites.add(request.user)
messages.success(request, f'Добавлено в избранное "{post.title}"')
# Перенаправить обратно на текущую страницу (HTTP_REFERER — это URL исходной страницы)
referer = request.META.get('HTTP_REFERER', '/')
return redirect(referer)
Краткий справочник по методам операций ManyToMany
| Методы | Функция | Пример |
|---|---|---|
| add(obj) | Добавление связи | post.favorites.add(user) |
| remove(obj) | Удаление связи | post.favorites.remove(user) |
| all() | Запрос всех связанных объектов | post.favorites.all() |
| filter(...) | Фильтрация по условиям | post.favorites.filter(id=1) |
| exists() | Определить, есть ли совпадающая запись | post.favorites.filter(id=1).exists() |
| clear() | Очистить все связи | post.favorites.clear() |
Настроить маршрут избранного
Пример
urlpatterns = [
# ... существующие маршруты ...
path('post/<int:pk>/favorite/', views.toggle_favorite, name='toggle_favorite'),
]
Добавить кнопку избранного на страницу подробностей
Пример
{% extends 'blog/base.html' %}
{% block title %}{{ post.title }} - ПРИМЕР Блог{% endblock %}
{% block content %}
<article class="post-view">
<span class="category-tag">{{ post.category.name }}</span>
<div class="post-header">
<h1>{{ post.title }}</h1>
<!-- Кнопка «В избранное»: видна только авторизованным пользователям -->
{% if user.is_authenticated %}
<form method="post" action="{% url 'toggle_favorite' post.pk %}">
{% csrf_token %}
<button type="submit" class="fav-btn">
{% if user in post.favorites.all %}
♥favorited
{% else %}
♡ В избранное
{% endif %}
</button>
</форма>
{% endif %}
</div>
<time>{{ post.created_at|date:"Y-m-d" }}</time>
<div class="content">{{ post.content|safe }}</div>
<a href="{% url 'index' %}" class="back-link">← На главную</a>
</article>
{% endblock %}
Также добавьте кнопку избранного на карточки статей на главной странице:
Пример
<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>
<div class="card-footer">
<span class="card-date">{{ post.created_at|date:"Y-m-d" }}</span>
{% if user.is_authenticated %}
<form method="post" action="{% url 'toggle_favorite' post.pk %}" class="fav-form">
{% csrf_token %}
<button type="submit" class="fav-btn-small">
{% if user in post.favorites.all %}♥{% else %}♡{% endif %}
</button>
</форма>
{% endif %}
</div>
</div>
</div>
Почему кнопка избранного использует форму вместо тега <a>? Потому что операция добавления в избранное изменяет базу данных и является POST-запросом. Согласно соглашениям REST, операции чтения используют GET, операции записи используют POST. Что важнее, POST-запросы несут
csrf_token...чтобы предотвратить подделку запросов вредоносными сайтами.
Страница списка избранного
Отобразить список статей, добавленных в избранное, для авторизованных пользователей.
Пример
@login_required
def favorites(request):
"""Список избранного текущего пользователя"""
# Используйте related_name для обратной выборки статей, добавленных пользователем в избранное
posts = request.user.favorite_posts.all().order_by('-created_at')
return render(request, 'blog/favorites.html', {
'posts': posts,
'title': 'Моё избранное - EXAMPLE Blog'
})
Добавьте маршрут в urls.py и добавьте ссылку «Моё избранное» в панель навигации.
Стиль кнопки избранного
Пример
.post-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.fav-btn, .fav-btn-small {
background: none;
border: none;
font-size: 18px;
cursor: pointer;
color: #e74c3c;
padding: 4px 8px;
transition: transform 0.2s;
}
.fav-btn:hover, .fav-btn-small:hover {
transform: scale(1.2);
}
.fav-btn-small {
font-size: 16px;
}
.fav-form {
display: inline;
}
.card-footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
Итоги главы
В этой главе вы освоили обработку взаимодействия с пользователем в Django: ManyToManyField для установления связей «многие ко многим», POST-запросы для обработки форм, csrf_token для обеспечения безопасности, декоратор login_required для защиты представлений и request.user для определения текущего пользователя.
Функция избранного позволяет пользователям отмечать статьи, которые им нравятся, и просматривать их в личном списке избранного.
Другие расширения