Fonctionnalité Formulaires et Favoris
Dans ce chapitre, vous apprendrez à gérer les requêtes POST des utilisateurs, à établir des relations plusieurs-à-plusieurs et à implémenter la fonctionnalité « articles favoris ».
Conception du modèle de données pour la fonctionnalité de favoris
Le cœur de la fonctionnalité de favoris est :Un utilisateur peut ajouter plusieurs articles à ses favoris, et un article peut être ajouté aux favoris par plusieurs utilisateurs.。
Il s'agit d'une relation plusieurs-à-plusieurs (ManyToMany) typique.
Nous n'avons pas besoin de créer un nouveau modèle — le modèle User de Django est intégré ; nous avons juste besoin d'ajouter un ManyToManyField pointant vers User dans le modèle Post.
Exemple
from django.contrib.auth.models import Utilisateur
class Post(models.Model):
# ... champs existants ...
# Collector : ManyToManyField crée automatiquement une table intermédiaire
favorites = models.ManyToManyField(
Utilisateur,
related_name='favorite_posts', # Requête inverse : user.favorite_posts.all()
verbose_name='collector',
blank=True
)
Après avoir modifié le modèle, générez et exécutez la migration :
(venv) $ python manage.py makemigrations (venv) $ python manage.py migrate
Logique de vue pour l'ajout et le retrait des favoris
Exemple
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
# décorateur login_required : lorsqu'un utilisateur non authentifié accède à cette vue, rediriger automatiquement vers la page de connexion
@login_required
def toggle_favorite(request, pk):
"""Basculer le statut favori : favori → retirer des favoris, non favori → ajouter aux favoris"""
post = get_object_or_404(Post, pk=pk)
# Vérifier si l'utilisateur actuel a ajouté aux favoris
if post.favorites.filter(id=request.user.id).exists():
# Favori → Retirer des favoris
post.favorites.remove(request.user)
messages.info(request, f'Retiré des favoris "{post.title}"')
else:
# Non favori → Ajouter aux favoris
post.favorites.add(request.user)
messages.success(request, f'Ajouté aux favoris "{post.title}"')
# Rediriger vers la page actuelle (HTTP_REFERER est l'URL de la page source)
referer = request.META.get('HTTP_REFERER', '/')
return redirect(referer)
Référence rapide des méthodes d'opération ManyToMany
| Méthodes | Fonction | Exemple |
|---|---|---|
| add(obj) | Ajouter une association | post.favorites.add(user) |
| remove(obj) | Supprimer une association | post.favorites.remove(user) |
| all() | Interroger tous les objets associés | post.favorites.all() |
| filter(...) | Filtrer avec des conditions | post.favorites.filter(id=1) |
| exists() | Déterminer s'il existe un enregistrement correspondant | post.favorites.filter(id=1).exists() |
| clear() | Effacer toutes les associations | post.favorites.clear() |
Configurer la route des favoris
Exemple
url = [
# ... routes existantes ...
path('post/<int:pk>/favorite/', views.toggle_favorite, name='toggle_favorite'),
]
Ajouter un bouton de favoris à la page de détail
Exemple
{% extends 'blog/base.html' %}
{% block title %}{{ post.title }} - Blog EXEMPLE{% endblock %}
{% block content %}
<article class="post-view">
<span class="category-tag">{{ post.category }}</span>
<div class="post-header">
<h1>{{ post.title }}</h1>
<!-- Bouton favori : visible uniquement par les utilisateurs connectés -->
{% 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 %}
♡ Favori
{% endif %}
</button>
</forme>
{% 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">← Retour à l'accueil</a>
</article>
{% endblock %}
Ajoutez également un bouton de favoris aux cartes d'articles sur la page d'accueil :
Exemple
<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>
</forme>
{% endif %}
</div>
</div>
</div>
Pourquoi le bouton favori utilise-t-il un formulaire au lieu d'une balise <a> ? Parce que l'opération de mise en favori modifie la base de données et est une requête POST. Selon les conventions REST, les opérations de lecture utilisent GET, les opérations d'écriture utilisent POST. Plus important encore, les requêtes POST transportent
csrf_token...pour empêcher des sites web malveillants de falsifier des requêtes.
Page de la liste des favoris
Afficher la liste des articles mis en favori pour les utilisateurs connectés.
Exemple
@login_required
def favorites(request):
"""Liste des favoris de l'utilisateur actuel"""
# Utiliser related_name pour effectuer une requête inversée sur les articles mis en favori par l'utilisateur
posts = request.user.favorite_posts.all().order_by('-created_at')
return render(request, 'blog/favorites.html', {
'posts': posts,
'title': 'Mes favoris - Blog EXEMPLE'
})
Ajoutez une route dans urls.py, et ajoutez un lien « Mes favoris » dans la barre de navigation.
Style du bouton des favoris
Exemple
.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;
}
Résumé du chapitre
Dans ce chapitre, vous avez maîtrisé la gestion des interactions utilisateur dans Django : ManyToManyField pour établir des relations plusieurs-à-plusieurs, les requêtes POST pour gérer les formulaires, csrf_token pour la protection de sécurité, le décorateur login_required pour protéger les vues, et request.user pour déterminer l'identité de l'utilisateur actuel.
La fonctionnalité de favoris permet aux utilisateurs de marquer les articles qu'ils aiment et de les consulter dans leur liste de favoris personnelle.
autres extensions