Klassenbasierte View (CBV) Refactoring

In diesem Kapitel lernen Sie Djangos klassenbasierte Views (CBV) kennen und refaktorieren die Startseite und die Detailseite mit prägnanterem Code.


FBV vs CBV

Bisher wurden alle unsere Views mit Funktionen geschrieben (Function-Based Views, FBV).

Django bietet außerdemClass-Based View (CBV), wobei Klassen verwendet werden, um die View-Logik zu kapseln.

FunktionenFBV (funktionsbasierte View)CBV (klassenbasierte Views)
CodeumfangFlexibel, aber gemeinsame Logik muss wiederholt geschrieben werdenNach der Vererbung der generischen View sind nur wenige Codezeilen nötig
LesbarkeitLinearer Ablauf, klare LogikDie Vererbungskette erfordert Nachverfolgung, aber sobald man damit vertraut ist, ist sie auf einen Blick klar.
WiederverwendbarkeitDurch Funktionen gekapseltVerwendung von Mixin-Komposition (ein Django-Markenzeichen)
Anwendbare SzenarienSeiten mit einfacher Logik und klarem AblaufMusterhafte Seiten wie Create, Read, Update, Delete (CRUD)
HTTP-Methoden-DispatchManuell if request.method == 'POST'Automatischer Dispatch an get()- / post()-Methoden

Es gibt keinen absoluten Vorteil oder Nachteil zwischen den beiden; Django-Projekte normalerweise...Mischung von FBV und CBV: Verwende FBV für komplexe Logik und CBV für Standard-CRUD.


ListView — Refactoring der Listenseite

Die Index-View der Startseite ist im Wesentlichen:Artikelliste abfragen → Template rendern。

Für diese Art von Musterlogik, Djangos...ListViewBereits für dich geschrieben.

Beispiel

# Dateipfad: blog/views.py
from django.views.generic import ListView
from django.db.models import Q
from .models import Post, Category

class PostListView(ListView):
    """Blog-Startseite: erbt von ListView, zeigt Artikelliste an"""
    model = Post                           # Modell angeben
    template_name = 'blog/index.html'       # Template angeben (Standard: blog/post_list.html)
    context_object_name = 'posts'           # Der im Template verwendete Variablenname (Standard: object_list)
    paginate_by = 12                        # 12 Elemente pro Seite (Paginierung)
    ordering = ['-created_at']             # Sortierung

    def get_queryset(self):
        """Überschreibt die Abfragemethode: unterstützt Kategorienfilterung + Stichwortsuche"""
        queryset = super().get_queryset()

        # Kategoriefilter
        self.category_slug = self.request.GET.get('category', '')
        if self.category_slug:
            queryset = queryset.filter(category__slug=self.category_slug)

        # Stichwortsuche
        self.keyword = self.request.GET.get('q', '')
        if self.keyword:
            queryset = queryset.filter(
                Q(title__icontains=self.keyword) |
                Q(summary__icontains=self.keyword)
            )

        return queryset

    def get_context_data(self, **kwargs):
        """Kontextmethode überschreiben: zusätzliche Daten in das Template einfügen"""
        context = super().get_context_data(**kwargs)
        context['categories'] = Category.objects.all()
        context['category_slug'] = self.category_slug
        context['keyword'] = self.keyword
        context['title'] = 'BEISPIEL Blog - Startseite'
        return context

Vergleiche den Codeumfang vor und nach dem Refactoring: FBV hat etwa 40 Zeilen → CBV hat etwa 30 Zeilen, und die Logik ist klar in verschiedene Methoden aufgeteilt.


DetailView — Refactoring der Detailseite

Beispiel

# Dateipfad: blog/views.py (neu hinzugefügt)
from django.views.generic import DetailView

class PostDetailView(DetailView):
    """Artikeldetailseite: erbt von DetailView"""
    model = Post
    template_name = 'blog/post_detail.html'
    context_object_name = 'post'

    # pk_url_kwarg: Parametername für die Übergabe des Primärschlüssels in der URL (Standard ist pk; hier explizit deklariert).
    pk_url_kwarg = 'pk'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'{self.object.title} - EXAMPLE Blog'
        return context

Routenkonfiguration aktualisieren

Die CBV-Routing-Syntax unterscheidet sich leicht von der FBV — sie erfordert den Aufruf....as_view()。

Beispiel

# Dateipfad: blog/urls.py
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views

urlpatterns = [
    # CBV: .as_view() nach der Klasse hinzufügen, um sie in eine View-Funktion umzuwandeln
    path('', views.PostListView.as_view(), name='index'),
    path('post/<int:pk>/', views.PostDetailView.as_view(), name='post_detail'),

    # Andere Ansichten bleiben unverändert
    path('register/', views.register, name='register'),
    path('login/', auth_views.LoginView.as_view(
        template_name='blog/login.html',
        redirect_authenticated_user=True
    ), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
    path('post/<int:pk>/favorite/', views.toggle_favorite, name='toggle_favorite'),
]

Warum CBV verwenden?.as_view()? Djangos URL-Konfiguration erwartet ein aufrufbares Objekt (Funktion)..as_view()Es wandelt die Klassenansicht in ein aufrufbares Objekt um, das der Signatur der Django-View-Funktion entspricht, und übernimmt intern automatisch die Weiterleitung an die get()- oder post()-Methode der Klasse basierend auf der HTTP-Methode (GET/POST).


Überblick über gängige generische Views

AnsichtStandard-Template-NameZweck
ListViewmodelname_list.htmlObjektliste anzeigen
DetailViewmodelname_detail.htmlDetails eines einzelnen Objekts anzeigen
CreateViewmodelname_form.htmlEin neues Objekt erstellen (mit Formular)
UpdateViewmodelname_form.htmlBestehendes Objekt aktualisieren
DeleteViewmodel_name_confirm_delete.htmlObjektlöschung bestätigen
TemplateViewmuss angegeben werdenStatische Vorlage rendern (keine Datenabfrage)

Djangos generische Views decken etwa 80% der Webentwicklungsszenarien ab. Wenn Sie auf Situationen stoßen, die Ihren Anforderungen nicht entsprechen, greifen Sie auf FBV zurück.


LoginRequiredMixin

CBV nicht verfügbar@login_requiredDekoratoren (diese sind für Funktionen), wechseln Sie zu...LoginRequiredMixin。

Beispiel

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView

class FavoriteListView(LoginRequiredMixin, ListView):
    """Favoritenliste: Anmeldung erforderlich für den Zugriff"""
    model = Post
    template_name = 'blog/favorites.html'
    context_object_name = 'posts'
    ordering = ['-created_at']

    # LoginRequiredMixin: Nicht authentifizierte Benutzer werden automatisch zu settings.LOGIN_URL weitergeleitet

    def get_queryset(self):
        # Nur Artikel anzeigen, die vom aktuellen Benutzer favorisiert wurden
        return self.request.user.favorite_posts.all().order_by('-created_at')

Die Vererbungsreihenfolge von Mixins ist sehr wichtig:LoginRequiredMixinMuss geschrieben werden inListViewFrüher. Pythons Auflösungsreihenfolge bei Mehrfachvererbung ist von links nach rechts; LoginRequiredMixin prüft zuerst den Anmeldestatus, und erst nach erfolgreicher Prüfung wird die ListView-Logik weiter ausgeführt.


Wann sollte man CBV verwenden und wann FBV?

Faustregel:

  • FBV: Views mit komplexer Logik, vielen bedingten Verzweigungen und nicht standardmäßigen Abläufen (wie toggle_favorite)
  • CBV: Views mit standardmäßigen CRUD-Operationen und Logik, die klar in get/post aufgeteilt werden kann (wie Listenseiten, Detailseiten)

Operationen wie toggle_favorite (Favoriten-Umschaltung) haben eine einfache Logik, aber einen von konventionellem CRUD abweichenden Ablauf; FBV ist geeigneter.

Für standardmäßige Datendarstellungsseiten wie index und post_detail kann CBV Boilerplate-Code erheblich reduzieren.


Kapitelzusammenfassung

In diesem Kapitel haben Sie die Kernverwendung von klassenbasierten Views in Django kennengelernt: ListView zeigt Listen an, DetailView zeigt Details an, get_queryset/get_context_data passen Abfragen und Kontext an, as_view() ermöglicht Routing, und LoginRequiredMixin ersetzt login_required.

Der refaktorierte Code für Startseite und Detailseite ist kürzer und hat eine klarere Struktur.

Weitere Erweiterungen