Der folgende Artikel ist der letzte Teil der Entdeckungsreihe zu Django klassengebundenen Ansichten (CBV), in dem erläutert wird, wie man ListView vertieft einsetzen kann, um Paging, Suche und Sortierung – Funktionen, die in der Praxis häufig verwendet werden – zu implementieren. Wenn Sie in den vorherigen 7 Teilen die Grundlagen von CBV bis zur Nutzung von Mixins behandelt haben, werden wir in diesem Teil zusammenfassen, wie die allgemeinen Anforderungen, die in der Webentwicklung auftreten, sauber mit CBV bearbeitet werden können.

Der Link zum vorherigen Teil finden Sie hier!

Klassengebundene Ansichten (CBV) Entdeckungsreihe ⑦ - Nutzung von Mixins und Berechtigungsverwaltung


„Erweitern Sie Django ListView, um leistungsstarke Listenfunktionen zu implementieren und

verbessern Sie die Benutzererfahrung!“


1. ListView, mehr Möglichkeiten

ListView ist eine äußerst nützliche generische Ansicht, um Datenlisten anzuzeigen. In einer realen Webanwendung sind jedoch zusätzlich zur einfachen Anzeige von Listen auch Paging erforderlich, um große Datenmengen effizient zu verwalten, Suche, um schnell die gewünschten Informationen zu finden, sowie Sortierungsfunktionalitäten, die auf den Benutzerpräferenzen basieren.

In diesem Abschnitt werden wir untersuchen, wie diese praktischen Anforderungen durch die Erweiterung von ListView elegant und einfach mit den Vorteilen von CBV implementiert werden können.


2. Paging anwenden

Eine große Menge an Daten auf einmal anzuzeigen, ist nicht gut für die Benutzererfahrung. Paging reduziert die Ladebelastung für den Benutzer, indem die Daten über mehrere Seiten verteilt werden, und hilft, die gewünschten Informationen leichter zu finden.

2.1 Grundlegende Paging-Einstellungen

ListView bietet eingebautes Paging. Es genügt, die paginate_by-Eigenschaft in der View-Klasse festzulegen.

Beispiel für views.py

from django.views.generic import ListView
from .models import Article

class ArticleListView(ListView):
    model = Article
    template_name = 'articles/article_list.html'
    context_object_name = 'articles'
    paginate_by = 10 # Zeigt 10 Artikel-Objekte pro Seite an
  • paginate_by = 10: Wenn Sie dies wie oben festlegen, wird ListView automatisch die Ergebnisse auf 10 pro Seite aufteilen und die pagingbezogenen Objekte (paginator, page_obj, is_paginated) an den Template-Kontext übergeben.

2.2 Paging-UI im Template implementieren

Im Template können Sie page_obj verwenden, um Seitenanzahl-Links anzuzeigen und Schaltflächen für vorherige/nächste Seiten zu implementieren.

Beispiel für articles/article_list.html

<ul>
    {% for article in articles %}
        <li>{{ article.title }} - {{ article.created_at }}</li>
    {% empty %}
        <li>Es sind noch keine Artikel veröffentlicht worden.</li>
    {% endfor %}
</ul>

<div class="pagination">
    <span class="step-links">
        {% if page_obj.has_previous %}
            <a href="?page=1">&laquo; Erster</a>
            <a href="?page={{ page_obj.previous_page_number }}>Vorherige</a>
        {% endif %}

        <span class="current">
            Seite {{ page_obj.number }} / {{ paginator.num_pages }}
        </span>

        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}>Nächste</a>
            <a href="?page={{ paginator.num_pages }}>Letzte &raquo;</a>
        {% endif %}
    </span>
</div>
  • page_obj: Objekt, das die Daten der aktuellen Seite enthält. Es bietet Eigenschaften wie has_previous, has_next, previous_page_number, next_page_number, number usw.
  • paginator: Objekt, das Informationen zu allen Seiten enthält. Es enthält Eigenschaften wie num_pages (Gesamtanzahl der Seiten).

2.3 URL-Verbindung aufrechterhalten

Wenn Sie Paging-Links erstellen, können Sie Parameter wie ?page=2 sehen. ListView erkennt diesen Parameter automatisch und zeigt die Daten der entsprechenden Seite an.


Es ist sehr wichtig, schnell Informationen auf der Website zu finden. Lassen Sie uns die Suchfunktion durch die Erweiterung von ListView implementieren.

3.1 Form definieren

Zunächst definieren wir ein einfaches Formular, um das Suchbegriff zu erfassen.

Beispiel für forms.py

from django import forms

class ArticleSearchForm(forms.Form):
    search_term = forms.CharField(label='Suchbegriff', required=False)

3.2 ListView modifizieren

Wir überschreiben die Methode get_queryset() von ListView, um die Suchfunktion zu implementieren.

Beispiel für views.py

from django.views.generic import ListView
from django.db.models import Q
from .models import Article
from .forms import ArticleSearchForm

class ArticleListView(ListView):
    model = Article
    template_name = 'articles/article_list.html'
    context_object_name = 'articles'
    paginate_by = 10

    def get_queryset(self):
        queryset = super().get_queryset()
        self.form = ArticleSearchForm(self.request.GET) # Holt die Formulardaten aus der GET-Anfrage

        if self.form.is_valid():
            search_term = self.form.cleaned_data.get('search_term')
            if search_term:
                # Artikel filtern, die den Suchbegriff im Titel oder Inhalt haben
                queryset = queryset.filter(
                    Q(title__icontains=search_term) | Q(content__icontains=search_term)
                )
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_form'] = self.form # Übertragen der Form im Template
        return context
  • get_queryset(): Diese Methode wird überschrieben, um das Standard-Queryset zu ändern.
  • Eine Instanz des Formulars wird erstellt, und nach der Validierung wird der Suchbegriff aus cleaned_data abgerufen.
  • Das Q-Objekt wird verwendet, um Artikel zu filtern, die den Suchbegriff im Titel (title) oder Inhalt (content) enthalten (__icontains prüft, ob der Begriff unabhängig von Groß- und Kleinschreibung enthalten ist).
  • get_context_data(): Fügt die Formularinstanz dem Kontext hinzu, damit sie im Template gerendert werden kann.

3.3 Suchformular im Template anzeigen und Ergebnisse beibehalten

Fügen Sie das Suchformular im Template hinzu und strukturieren Sie die URL, um die Suchergebnisse beizubehalten, während das Paging erfolgt.

Beispiel für articles/article_list.html

<form method="get">
    {{ search_form }}
    <button type="submit">Suchen</button>
</form>

<ul>
    {% for article in articles %}
        <li>{{ article.title }} - {{ article.created_at }}</li>
    {% empty %}
        <li>Es wurden keine Suchergebnisse gefunden.</li>
    {% endfor %}
</ul>

<div class="pagination">
    <span class="step-links">
        {% if page_obj.has_previous %}
            <a href="?page=1&search_term={{ search_form.search_term.value|default:'' }}">&laquo; Erster</a>
            <a href="?page={{ page_obj.previous_page_number }}&search_term={{ search_form.search_term.value|default:'' }}">Vorherige</a>
        {% endif %}

        <span class="current">
            Seite {{ page_obj.number }} / {{ paginator.num_pages }}
        </span>

        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}&search_term={{ search_form.search_term.value|default:'' }}">Nächste</a>
            <a href="?page={{ paginator.num_pages }}&search_term={{ search_form.search_term.value|default:'' }}">Letzte &raquo;</a>
        {% endif %}
    </span>
</div>
  • Das method des Formulars wird auf get gesetzt, um den Suchbegriff als URL-Abfrageparameter zu übertragen.
  • Beim Erstellen der Seitenlinks wird der aktuelle Suchbegriff (search_form.search_term.value) in die URL-Parameter aufgenommen, um die Suchergebnisse beim Paging zu erhalten. Der |default:''-Filter verwendet eine leere Zeichenfolge, wenn kein Suchbegriff vorhanden ist.

Beispiel für ListView-Oberfläche – mit Such- und Sortierungs-UI integrierte Listenansicht


4. Sortierfunktion hinzufügen

Lassen Sie uns eine Sortierfunktion hinzufügen, damit die Benutzer Daten nach ihren gewünschten Kriterien sortieren können.

4.1 Zusätzliche Sortierauswahl (optional)

Sie können auch ein Dropdown-Formular hinzufügen, um die Sortierkriterien auszuwählen. Einfacher kann dies auch über URL-Parameter erfolgen. Hier beschreiben wir die Methode mit URL-Parametern.

4.2 ListView modifizieren

Modifizieren Sie die Methode get_queryset(), um order_by() anzuwenden.

Beispiel für views.py (inkl. Suchfunktion)

from django.views.generic import ListView
from django.db.models import Q
from .models import Article
from .forms import ArticleSearchForm

class ArticleListView(ListView):
    model = Article
    template_name = 'articles/article_list.html'
    context_object_name = 'articles'
    paginate_by = 10

    def get_queryset(self):
        queryset = super().get_queryset()
        self.form = ArticleSearchForm(self.request.GET)
        ordering = self.request.GET.get('ordering', '-created_at') # Standard-Sortierung: nach Neueste

        if self.form.is_valid():
            search_term = self.form.cleaned_data.get('search_term')
            if search_term:
                queryset = queryset.filter(
                    Q(title__icontains=search_term) | Q(content__icontains=search_term)
                )

        queryset = queryset.order_by(ordering)
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_form'] = self.form
        context['ordering'] = self.request.GET.get('ordering', '-created_at') # Aktuelles Sortierkriterium an das Template übergeben
        return context
  • self.request.GET.get('ordering', '-created_at'): Holt den Wert ordering aus den URL-Abfrageparametern. Wenn kein Wert vorhanden ist, wird standardmäßig nach -created_at (neueste) sortiert.
  • queryset = queryset.order_by(ordering): Diese Zeile sortiert das Queryset mit dem abgerufenen ordering-Wert. Ein negative Zeichen vor dem Feldnamen sorgt für eine umgekehrte Sortierung.

4.3 Sortier-Links im Template bereitstellen

Sie stellen Links im Template zur Verfügung, um nach jedem Feld sortieren zu können.

Beispiel für articles/article_list.html

<form method="get">
    {{ search_form }}
    <button type="submit">Suchen</button>
</form>

<table>
    <thead>
        <tr>
            <th><a href="?ordering=title&search_term={{ search_form.search_term.value|default:'' }}">Titel</a></th>
            <th><a href="?ordering=-created_at&search_term={{ search_form.search_term.value|default:'' }}">Erstellungsdatum</a></th>
            </tr>
    </thead>
    <tbody>
        {% for article in articles %}
            <tr>
                <td>{{ article.title }}</td>
                <td>{{ article.created_at }}</td>
            </tr>
        {% empty %}
            <tr><td colspan="2">Es wurden keine Suchergebnisse gefunden.</td></tr>
        {% endfor %}
    </tbody>
</table>

<div class="pagination">
    <span class="step-links">
        {% if page_obj.has_previous %}
            <a href="?page=1&search_term={{ search_form.search_term.value|default:'' }}&ordering={{ ordering }}">&laquo; Erster</a>
            <a href="?page={{ page_obj.previous_page_number }}&search_term={{ search_form.search_term.value|default:'' }}&ordering={{ ordering }}">Vorherige</a>
        {% endif %}

        <span class="current">
            Seite {{ page_obj.number }} / {{ paginator.num_pages }}
        </span>

        {% if page_obj.has_next %}
            <a href="?page={{ page_obj.next_page_number }}&search_term={{ search_form.search_term.value|default:'' }}&ordering={{ ordering }}">Nächste</a>
            <a href="?page={{ paginator.num_pages }}&search_term={{ search_form.search_term.value|default:'' }}&ordering={{ ordering }}">Letzte &raquo;</a>
        {% endif %}
    </span>
</div>
  • Jede Tabellenkopfzeile enthält Links mit ordering-Parametern.
  • Bei der Erstellung der Seitenlinks werden sowohl der aktuelle Suchbegriff als auch die aktuellen Sortierkriterien (ordering) in die URL-Parameter aufgenommen, um den Sortierstatus beim Paging beizubehalten.

Such-/Sortierungsprozessdiagramm - Visualisierung des ListView-Erweiterungsflusses


5. Funktionen mit Mixin kombinieren

Durch die Verwendung von Mixins, die wir zuvor gelernt haben, können Sie Paging, Such- und Sortierfunktionen noch klarer verwalten. Beispielsweise kann die Suchfunktion in ein Mixin ausgelagert werden.

Beispiel für mixins.py

from django.db.models import Q
from .forms import ArticleSearchForm

class ArticleSearchMixin:
    def get_queryset(self):
        queryset = super().get_queryset()
        self.form = ArticleSearchForm(self.request.GET)

        if self.form.is_valid():
            search_term = self.form.cleaned_data.get('search_term')
            if search_term:
                queryset = queryset.filter(
                    Q(title__icontains=search_term) | Q(content__icontains=search_term)
                )
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_form'] = getattr(self, 'form', ArticleSearchForm()) # Standardformular verwenden, falls kein Formular vorhanden ist
        return context

Beispiel für views.py (Mixin angewendet)

from django.views.generic import ListView
from .models import Article
from .mixins import ArticleSearchMixin

class ArticleListView(ArticleSearchMixin, ListView):
    model = Article
    template_name = 'articles/article_list.html'
    context_object_name = 'articles'
    paginate_by = 10

    def get_queryset(self):
        queryset = super().get_queryset()
        ordering = self.request.GET.get('ordering', '-created_at')
        queryset = queryset.order_by(ordering)
        return queryset

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['ordering'] = self.request.GET.get('ordering', '-created_at')
        return context
  • Wir haben ein ArticleSearchMixin erstellt, um die Logik im Zusammenhang mit der Suche zu trennen.
  • Die ArticleListView erbt sowohl von ArticleSearchMixin als auch von ListView, um sowohl Such- als auch Listenfunktionen zu integrieren.

6. Vorteile und Grenzen von CBV (Abschluss der Reihe)

In dieser achtteiligen Entdeckungsreihe zu CBV haben wir untersucht, warum man von funktionsbasierten Ansichten (FBV) zu klassengebundenen Ansichten (CBV) wechselt, die grundlegende Struktur und Anwendung von CBV, die Nutzung verschiedener generischer Ansichten sowie die Erweiterung von Funktionen mittels Mixin.

Hauptvorteile von CBV:

  • Wiederverwendbarkeit des Codes: Durch generische Ansichten und Mixins können wiederholte Codes reduziert und effiziente Entwicklungen durchgeführt werden.
  • Strukturierter Code: Der klassenbasierte Code trennt die Logik klar und macht die Verwaltung einfacher.
  • Erweiterbarkeit: Funktionen lassen sich durch Vererbung und Mixins leicht erweitern und neue Funktionen hinzufügen.
  • Wartbarkeit: Der modularisierte Code ermöglicht eine einfache Wartung und verringert die Auswirkungen von Änderungen auf den gesamten Code.
  • Produktivitätssteigerung in der Entwicklung: Durch die Verwendung von verschiedenen generischen Ansichten und Mixins von Django kann schnell entwickelt werden.

Nachteile und Überlegungen zu CBV:

  • Einstiegshürde: Im Vergleich zu FBV kann ein Verständnis für die klassenbasierte Struktur erforderlich sein.
  • Übermäßige Vererbung: Wenn zu viele Mixins verwendet werden, kann es schwierig werden, den Codefluss zu verstehen. Ein angemessener Einsatz von Mixins ist wichtig.
  • Überengineering bei einfachen Logiken: Bei sehr einfachen Seiten oder Funktionen kann FBV einfacher sein. Es ist ratsam, je nach Situation die geeignete Ansichtsmethode auszuwählen.

Zusammenfassend lässt sich sagen, dass Django CBV ein äußerst leistungsfähiges und nützliches Werkzeug für die Entwicklung von Webanwendungen mit komplexen und vielfältigen Funktionen ist. Wenn Sie die Vorteile von CBV verstehen und angemessen nutzen, können Sie effizienteren und wartungsfreundlicheren Code schreiben.

Vielen Dank, dass Sie die Entdeckungsreihe zu klassengebundenen Ansichten (CBV) gelesen haben! Ich hoffe, dass diese Reihe Ihnen hilft, CBV in Django zu verstehen und in realen Projekten anzuwenden.


Frühere Artikel erneut ansehen

  1. Klassengebundene Ansichten (CBV) Entdeckungsreihe #1 – Der Grund für den Wechsel von FBV zu CBV und die Einstellung von Entwicklern
  2. Klassengebundene Ansichten (CBV) Entdeckungsreihe #2 – Grundlegende View-Klassen in Django verstehen
  3. Klassengebundene Ansichten (CBV) Entdeckungsreihe #3 – Einfache Formularverarbeitung mit FormView
  4. Klassengebundene Ansichten (CBV) Entdeckungsreihe #4 – Nutzung von ListView & DetailView
  5. Klassengebundene Ansichten (CBV) Entdeckungsreihe #5 – CRUD mit CreateView, UpdateView, DeleteView implementieren
  6. Klassengebundene Ansichten (CBV) Entdeckungsreihe #6 – Nutzung von TemplateView & RedirectView
  7. Klassengebundene Ansichten (CBV) Entdeckungsreihe #7 – Nutzung von Mixins und Berechtigungsverwaltung

„Implementieren Sie durch die Erweiterung von ListView eine umfangreiche und benutzerfreundliche Listenfunktion und

steigen Sie mit dem Mastering von CBV auf ein neues Niveau in Ihrer Django-Entwicklung!“