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.
| Funktionen | FBV (funktionsbasierte View) | CBV (klassenbasierte Views) |
|---|---|---|
| Codeumfang | Flexibel, aber gemeinsame Logik muss wiederholt geschrieben werden | Nach der Vererbung der generischen View sind nur wenige Codezeilen nötig |
| Lesbarkeit | Linearer Ablauf, klare Logik | Die Vererbungskette erfordert Nachverfolgung, aber sobald man damit vertraut ist, ist sie auf einen Blick klar. |
| Wiederverwendbarkeit | Durch Funktionen gekapselt | Verwendung von Mixin-Komposition (ein Django-Markenzeichen) |
| Anwendbare Szenarien | Seiten mit einfacher Logik und klarem Ablauf | Musterhafte Seiten wie Create, Read, Update, Delete (CRUD) |
| HTTP-Methoden-Dispatch | Manuell 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
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
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
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
| Ansicht | Standard-Template-Name | Zweck |
|---|---|---|
| ListView | modelname_list.html | Objektliste anzeigen |
| DetailView | modelname_detail.html | Details eines einzelnen Objekts anzeigen |
| CreateView | modelname_form.html | Ein neues Objekt erstellen (mit Formular) |
| UpdateView | modelname_form.html | Bestehendes Objekt aktualisieren |
| DeleteView | model_name_confirm_delete.html | Objektlöschung bestätigen |
| TemplateView | muss angegeben werden | Statische 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.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