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

# Dateipfad: zur Post-Klasse in blog/models.py hinzufügen
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

# Dateipfad: blog/views.py (neu hinzugefügt)
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

MethodenFunktionBeispiel
add(obj)Assoziation hinzufügenpost.favorites.add(user)
remove(obj)Assoziation entfernenpost.favorites.remove(user)
all()Alle zugehörigen Objekte abfragenpost.favorites.all()
filter(...)Mit Bedingungen filternpost.favorites.filter(id=1)
exists()Ermitteln, ob ein übereinstimmender Datensatz vorhanden istpost.favorites.filter(id=1).exists()
clear()Alle Verknüpfungen löschenpost.favorites.clear()

Favoriten-Route konfigurieren

Beispiel

# Dateipfad: An blog/urls.py anhängen
urlpatterns = [
    # ... vorhandene Routen ...
    path('post/<int:pk>/favorite/', views.toggle_favorite, name='toggle_favorite'),
]

Favoriten-Schaltfläche zur Detailseite hinzufügen

Beispiel

<!-- Dateipfad: blog/templates/blog/post_detail.html (geändert) -->
{% 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 %}
                    &#x2665;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

<!-- Fügen Sie einen Favoriten-Button zur Artikelkarte in index.html hinzu (Fußzeilenbereich) -->
<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 %}&#x2665;{% 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 tragencsrf_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

# Dateipfad: blog/views.py (neu hinzugefügt)
@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

/* An den Stil in base.html anhängen */
.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