Formulare und Favoriten-Funktion
In diesem Kapitel lernst du, POST-Anfragen von Benutzern zu verarbeiten, Viele-zu-viele-Beziehungen einzurichten und die Funktion „Artikel favorisieren“ zu implementieren.
Datenmodell-Design für die Favoriten-Funktion
Der Kern der Favoriten-Funktion ist:Ein Benutzer kann mehrere Beiträge favorisieren, und ein Beitrag kann von mehreren Benutzern favorisiert werden.。
Dies ist eine typische Viele-zu-viele-Beziehung (ManyToMany).
Wir müssen kein neues Modell erstellen — Djangos User-Modell ist integriert; wir müssen nur ein ManyToManyField hinzufügen, das im Post-Modell auf User verweist.
Beispiel
from django.contrib.auth.models import Benutzer
class Post(models.Model):
# ... vorhandene Felder ...
# Collector: ManyToManyField erstellt automatisch eine Zwischentabelle
favorites = models.ManyToManyField(
Benutzer,
related_name='favorite_posts', # Umgekehrte Abfrage: user.favorite_posts.all()
verbose_name='collector',
blank=True
)
Nach dem Ändern des Modells die Migration generieren und ausführen:
(venv) $ python manage.py makemigrations (venv) $ python manage.py migrate
View-Logik zum Favorisieren und Entfernen aus Favoriten
Beispiel
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-Dekorator: Wenn ein nicht authentifizierter Benutzer auf diese View zugreift, automatisch zur Anmeldeseite weiterleiten
@login_required
def toggle_favorite(request, pk):
"""Favoritenstatus umschalten: favorisiert → aus Favoriten entfernen, nicht favorisiert → zu Favoriten hinzufügen"""
post = get_object_or_404(Post, pk=pk)
# Prüfen, ob der aktuelle Benutzer favorisiert hat
if post.favorites.filter(id=request.user.id).exists():
# Favorisiert → Aus Favoriten entfernen
post.favorites.remove(request.user)
messages.info(request, f'Aus Favoriten entfernt "{post.title}"')
else:
# Nicht favorisiert → Zu Favoriten hinzufügen
post.favorites.add(request.user)
messages.success(request, f'Zu Favoriten hinzugefügt "{post.title}"')
# Zurück zur aktuellen Seite weiterleiten (HTTP_REFERER ist die URL der Quellseite)
referer = request.META.get('HTTP_REFERER', '/')
return redirect(referer)
Kurzreferenz für ManyToMany-Operationsmethoden
| Methoden | Funktion | Beispiel |
|---|---|---|
| add(obj) | Assoziation hinzufügen | post.favorites.add(user) |
| remove(obj) | Assoziation entfernen | post.favorites.remove(user) |
| all() | Alle zugehörigen Objekte abfragen | post.favorites.all() |
| filter(...) | Mit Bedingungen filtern | post.favorites.filter(id=1) |
| exists() | Ermitteln, ob ein übereinstimmender Datensatz vorhanden ist | post.favorites.filter(id=1).exists() |
| clear() | Alle Verknüpfungen löschen | post.favorites.clear() |
Favoriten-Route konfigurieren
Beispiel
urlpatterns = [
# ... vorhandene Routen ...
path('post/<int:pk>/favorite/', views.toggle_favorite, name='toggle_favorite'),
]
Favoriten-Schaltfläche zur Detailseite hinzufügen
Beispiel
{% extends 'blog/base.html' %}
{% block title %}{{ post.title }} - BEISPIEL Blog{% endblock %}
{% block content %}
<article class="post-view">
<span class="category-tag">{{ post.category.name }}</span>
<div class="post-header">
<h1>{{ post.title }}</h1>
<!-- Favoriten-Button: Nur für angemeldete Benutzer sichtbar -->
{% 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 %}
♡ Favorit
{% endif %}
</button>
</Form>
{% 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">← Zurück zur Startseite</a>
</article>
{% endblock %}
Fügen Sie außerdem einen Favoriten-Button zu den Artikelkarten auf der Startseite hinzu:
Beispiel
<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>
</Form>
{% endif %}
</div>
</div>
</div>
Warum verwendet der Favoriten-Button ein Formular anstelle eines <a>-Tags? Weil die Favoriten-Operation die Datenbank ändert und eine POST-Anfrage ist. Gemäß den REST-Konventionen verwenden Leseoperationen GET, Schreiboperationen POST. Wichtiger noch: POST-Anfragen tragen
csrf_token...um zu verhindern, dass bösartige Websites Anfragen fälschen.
Favoritenliste-Seite
Zeigt die Liste der favorisierten Artikel für angemeldete Benutzer an.
Beispiel
@login_required
def favorites(request):
"""Current user's favorites list"""
# Verwende related_name, um die favorisierten Artikel des Benutzers umgekehrt abzufragen
posts = request.user.favorite_posts.all().order_by('-created_at')
return render(request, 'blog/favorites.html', {
'posts': posts,
'title': 'Meine Favoriten - EXAMPLE Blog'
})
Füge eine Route in urls.py hinzu und füge einen Link "Meine Favoriten" in der Navigationsleiste hinzu.
Favoriten-Button-Stil
Beispiel
.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;
}
Kapitelzusammenfassung
In diesem Kapitel hast du die Handhabung von Benutzerinteraktionen in Django gemeistert: ManyToManyField, um Many-to-Many-Beziehungen herzustellen, POST-Anfragen zur Verarbeitung von Formularen, csrf_token zum Sicherheitsschutz, login_required-Dekorator zum Schutz von Views und request.user zur Bestimmung der Identität des aktuellen Benutzers.
Die Favoriten-Funktion ermöglicht es Benutzern, Artikel, die ihnen gefallen, zu markieren und sie in ihrer persönlichen Favoritenliste anzuzeigen.
Weitere Erweiterungen