Django Admin Anpassung 2026: Actions, Filter und Interviewfragen
Umfassende Anleitung zur Django Admin Anpassung mit list_display, SimpleListFilter, Custom Actions und Facetten. Inklusive häufiger Interviewfragen für Django-Entwickler.

Die Anpassung des Django Admin verwandelt das integrierte Interface von einem einfachen Gerüst in ein maßgeschneidertes Backoffice für Produktionsanwendungen. Django 6 liefert erweiterte Admin-Funktionen wie Facettenzähler für Filter, anpassbare Passwortänderungsformulare und Font Awesome Icons, wodurch ein gut konfigurierter Admin tatsächlich angenehm zu bedienen ist.
ModelAdmin ist die zentrale Klasse für alle Admin-Anpassungen. Die Beherrschung von list_display, list_filter, search_fields, fieldsets und benutzerdefinierten Actions deckt 90% der Admin-Konfigurationsanforderungen ab.
ModelAdmin Grundlagen: list_display und search_fields
list_display steuert, welche Spalten auf der Änderungslistenseite erscheinen. Über einfache Feldnamen hinaus akzeptiert es Callables, die mit @admin.display() für berechnete Werte dekoriert sind. search_fields aktiviert das Suchfeld, das Datensätze standardmäßig mit icontains filtert.
# admin.py
from django.contrib import admin
from django.utils.html import format_html
from .models import Article
class ArticleAdmin(admin.ModelAdmin):
list_display = ["title", "author_name", "status", "publish_date", "is_recent"]
search_fields = ["title", "author__email", "content"]
list_per_page = 50
list_select_related = ["author"] # Avoid N+1 queries
@admin.display(description="Author", ordering="author__last_name")
def author_name(self, obj):
return f"{obj.author.first_name} {obj.author.last_name}"
@admin.display(description="Recent?", boolean=True)
def is_recent(self, obj):
from django.utils import timezone
return obj.publish_date >= timezone.now() - timezone.timedelta(days=7)
admin.site.register(Article, ArticleAdmin)Der @admin.display()-Dekorator ersetzt das ältere Muster, short_description als Funktionsattribut zu setzen. Der Parameter boolean=True rendert ein Häkchen- oder X-Symbol anstelle von True/False-Text. Die Verwendung von list_select_related verhindert N+1-Abfragen beim Zugriff auf Fremdschlüsselfelder in list_display.
Benutzerdefinierte list_filter mit SimpleListFilter
list_filter aktiviert Seitenleistenfilter auf der Änderungslistenseite. Feldnamen funktionieren für einfache Filterung, aber SimpleListFilter behandelt komplexe Filterlogik, die mehrere Felder umfasst oder benutzerdefinierte Abfragen erfordert.
# admin.py
from datetime import date, timedelta
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
from .models import Article
class PublishDateFilter(admin.SimpleListFilter):
title = _("publish period")
parameter_name = "published" # URL parameter: ?published=this_week
def lookups(self, request, model_admin):
# Returns (value, label) tuples for the filter sidebar
return [
("this_week", _("This week")),
("this_month", _("This month")),
("this_year", _("This year")),
("unpublished", _("Not published")),
]
def queryset(self, request, queryset):
# Filter the queryset based on self.value()
today = date.today()
if self.value() == "this_week":
return queryset.filter(publish_date__gte=today - timedelta(days=7))
if self.value() == "this_month":
return queryset.filter(
publish_date__year=today.year, publish_date__month=today.month
)
if self.value() == "this_year":
return queryset.filter(publish_date__year=today.year)
if self.value() == "unpublished":
return queryset.filter(publish_date__isnull=True)
return queryset
class ArticleAdmin(admin.ModelAdmin):
list_filter = [
"status",
PublishDateFilter,
("author", admin.RelatedOnlyFieldListFilter), # Show only authors with articles
]RelatedOnlyFieldListFilter beschränkt das Autoren-Dropdown auf Autoren, die tatsächlich Artikel haben, anstatt jeden Benutzer in der Datenbank aufzulisten. Dies verbessert die Benutzerfreundlichkeit, wenn das zugehörige Modell viele Datensätze hat.
Django 6 Facetten: Filteranzahlen in der Seitenleiste
Django 6 führte Facettenzähler ein, die die Anzahl der übereinstimmenden Objekte neben jeder Filteroption anzeigen. Das Attribut show_facets steuert dieses Verhalten.
# admin.py
from django.contrib import admin
from django.contrib.admin import ShowFacets
from .models import Article
class ArticleAdmin(admin.ModelAdmin):
list_display = ["title", "status", "category"]
list_filter = ["status", "category", "author"]
show_facets = ShowFacets.ALWAYS # Always display counts
# Alternative values:
# ShowFacets.ALLOW - Show counts when ?_facets=1 in URL
# ShowFacets.NEVER - Never show counts (for large datasets)Facettenzähler führen zusätzliche COUNT-Abfragen für jede Filteroption aus. Bei Tabellen mit Millionen von Zeilen sollte show_facets = ShowFacets.NEVER gesetzt werden, um Leistungseinbußen zu vermeiden. Die Zähler aktualisieren sich dynamisch, wenn Filter angewendet werden, und zeigen, wie viele Datensätze der aktuellen Filterkombination entsprechen.
Benutzerdefinierte Admin Actions für Massenoperationen
Admin Actions führen Massenoperationen auf ausgewählten Objekten durch. Der @admin.action-Dekorator legt Berechtigungen und die im Dropdown angezeigte Beschreibung fest.
# admin.py
from django.contrib import admin
from django.contrib import messages
from django.utils.translation import ngettext
from .models import Article
@admin.action(description="Publish selected articles", permissions=["change"])
def publish_articles(modeladmin, request, queryset):
# Exclude already published articles
unpublished = queryset.exclude(status="published")
updated = unpublished.update(status="published")
modeladmin.message_user(
request,
ngettext(
"%d article was published.",
"%d articles were published.",
updated,
)
% updated,
messages.SUCCESS,
)
@admin.action(description="Export selected as JSON")
def export_as_json(modeladmin, request, queryset):
from django.http import HttpResponse
from django.core import serializers
response = HttpResponse(content_type="application/json")
response["Content-Disposition"] = 'attachment; filename="articles.json"'
serializers.serialize("json", queryset, stream=response)
return response # Returning HttpResponse triggers file download
class ArticleAdmin(admin.ModelAdmin):
actions = [publish_articles, export_as_json]
def get_actions(self, request):
# Conditionally remove actions based on user permissions
actions = super().get_actions(request)
if not request.user.has_perm("articles.delete_article"):
del actions["delete_selected"]
return actionsDie Rückgabe einer HttpResponse aus einer Action löst einen Dateidownload aus oder leitet zu einer Bestätigungsseite weiter. Der Parameter permissions beschränkt die Action auf Benutzer mit bestimmten Modellberechtigungen. Das Überschreiben von get_actions() ermöglicht das dynamische Ein- oder Ausblenden von Actions basierend auf der aktuellen Anfrage.
Bereit für deine Django-Interviews?
Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.
Fieldsets und Inline-Modelle für organisierte Formulare
fieldsets organisiert die Hinzufügen- und Änderungsformulare in zusammenklappbare Abschnitte. TabularInline und StackedInline betten zugehörige Modelle direkt in das übergeordnete Formular ein und eliminieren die Navigation zwischen Seiten.
# admin.py
from django.contrib import admin
from .models import Article, ArticleImage, ArticleComment
class ArticleImageInline(admin.TabularInline):
model = ArticleImage
extra = 1 # Number of empty forms to display
max_num = 5 # Maximum images per article
fields = ["image", "caption", "order"]
class ArticleCommentInline(admin.StackedInline):
model = ArticleComment
extra = 0
readonly_fields = ["created_at", "author"]
can_delete = True
class ArticleAdmin(admin.ModelAdmin):
fieldsets = [
(
None,
{
"fields": ["title", "slug", "author"],
},
),
(
"Content",
{
"fields": ["content", "excerpt"],
"classes": ["wide"], # Full-width fields
},
),
(
"Publishing",
{
"fields": ["status", "publish_date", "category", "tags"],
"classes": ["collapse"], # Collapsed by default
},
),
(
"SEO",
{
"fields": ["meta_title", "meta_description"],
"classes": ["collapse"],
"description": "Search engine optimization fields",
},
),
]
inlines = [ArticleImageInline, ArticleCommentInline]
prepopulated_fields = {"slug": ["title"]} # Auto-generate slug from title
autocomplete_fields = ["author", "category"] # AJAX-powered select
filter_horizontal = ["tags"] # Widget for M2M selection
admin.site.register(Article, ArticleAdmin)TabularInline zeigt zugehörige Objekte in einem kompakten Tabellenformat an, geeignet für einfache Modelle mit wenigen Feldern. StackedInline zeigt jedes zugehörige Objekt als separaten Formularblock, besser für Modelle mit vielen Feldern. Die Option autocomplete_fields ersetzt das Standard-Dropdown durch ein AJAX-Suchwidget, unverzichtbar wenn das zugehörige Modell Tausende von Datensätzen hat.
Anpassung der Admin-Site
Das Erstellen von Unterklassen von AdminSite ermöglicht mehrere Admin-Interfaces mit unterschiedlichem Branding, Berechtigungen oder Modellregistrierungen. Django 6 fügte die Anpassung von password_change_form für strengere Passwortrichtlinien hinzu.
# admin.py
from django.contrib import admin
from django.contrib.admin import AdminSite
from .models import Article, Category
class ContentAdminSite(AdminSite):
site_header = "Content Management"
site_title = "CMS"
index_title = "Dashboard"
def has_permission(self, request):
# Restrict to staff in the 'editors' group
return (
request.user.is_active
and request.user.is_staff
and request.user.groups.filter(name="editors").exists()
)
content_admin = ContentAdminSite(name="content_admin")
content_admin.register(Article, ArticleAdmin)
content_admin.register(Category)
# In urls.py:
# path('content-admin/', content_admin.urls),Jede AdminSite-Instanz hat ihren eigenen URL-Namespace, Login-Seite und Satz registrierter Modelle. Dieses Muster eignet sich für Anwendungen mit unterschiedlichen Benutzerrollen, bei denen Redakteure keine Benutzerverwaltung oder Systemeinstellungen sehen sollten.
Interviewfragen: Django Admin Anpassung
Diese Fragen erscheinen häufig in technischen Django-Interviews. Das Verständnis der zugrunde liegenden Mechanismen, nicht nur der Syntax, unterscheidet Mid-Level-Kandidaten von Senior Engineers.
F: Wie fügt man eine berechnete Spalte zu list_display hinzu, die nicht sortierbar ist?
Der @admin.display()-Dekorator akzeptiert einen ordering-Parameter, der angibt, welches Datenbankfeld für die Sortierung verwendet werden soll. Ohne diesen ist die Spaltenüberschrift nicht anklickbar. Berechnete Werte, die mehrere Datensätze aggregieren oder externe Dienste aufrufen, können nicht sortiert werden, da es keine zugrunde liegende Datenbankspalte gibt, nach der sortiert werden kann.
F: Was ist die Leistungsauswirkung von Facettenzählern und wann sollten sie deaktiviert werden?
Facetten führen eine COUNT-Abfrage pro Filteroption aus, multipliziert mit der Anzahl aktiver Filter. Bei einer Tabelle mit 10 Millionen Zeilen und jeweils 5 Filteroptionen auf 3 Feldern sind das 15 zusätzliche COUNT-Abfragen pro Seitenaufruf. show_facets = ShowFacets.NEVER sollte gesetzt werden, wenn ein Filter auf eine Tabelle mit über 100.000 Zeilen ohne entsprechende Indizes zielt.
F: Wie unterscheiden sich Admin Actions von benutzerdefinierten Admin-Views?
Actions arbeiten mit einem Queryset ausgewählter Objekte und integrieren sich mit den Auswahlcheckboxen der Änderungsliste. Benutzerdefinierte Admin-Views sind eigenständige Seiten, auf die über benutzerdefinierte URLs zugegriffen wird, geeignet für Berichte, Importe oder Dashboards, die nicht mit ausgewählten Datensätzen arbeiten. Actions sollten keine lang laufenden Operationen durchführen, da sie die Anfrage blockieren.
F: Warum RelatedOnlyFieldListFilter anstelle des Standardfilters verwenden?
Der Standard-RelatedFieldListFilter fragt alle Objekte in der zugehörigen Tabelle ab. Wenn ein ForeignKey auf ein User-Modell mit 100.000 Datensätzen zeigt, lädt das Filter-Dropdown alle 100.000 Optionen und lässt den Browser einfrieren. RelatedOnlyFieldListFilter fragt nur die Werte ab, die in den Datensätzen des aktuellen Modells existieren, typischerweise eine viel kleinere Menge.
Häufige Fehler in der Produktion vermeiden
Mehrere Muster, die in der Entwicklung funktionieren, verursachen Probleme bei der Skalierung.
# admin.py
from django.contrib import admin
from .models import Order
class OrderAdmin(admin.ModelAdmin):
# Mistake: Accessing related fields without list_select_related
# This causes N+1 queries, one per row in the list view
list_display = ["id", "customer_email", "total"]
# Fix: Prefetch related objects
list_select_related = ["customer"]
def customer_email(self, obj):
return obj.customer.email
# Mistake: search_fields on unindexed large text columns
# search_fields = ["notes"] # Slow on large tables
# Fix: Limit search to indexed fields
search_fields = ["id", "customer__email"]
# Mistake: Expensive computation in list_display
# def order_total(self, obj):
# return sum(item.price * item.qty for item in obj.items.all()) # N+1
# Fix: Use annotation in get_queryset
def get_queryset(self, request):
from django.db.models import Sum, F
qs = super().get_queryset(request)
return qs.annotate(computed_total=Sum(F("items__price") * F("items__qty")))
@admin.display(description="Total", ordering="computed_total")
def total(self, obj):
return obj.computed_totalDas Überschreiben von get_queryset() zum Hinzufügen von Annotationen hält berechnete Werte in einer einzigen Abfrage, anstatt die Datenbank einmal pro Zeile abzufragen. Der Admin sollte mit der Django Debug Toolbar profiliert werden, um N+1-Abfragen zu erkennen, bevor sie die Produktion erreichen.
Drittanbieter-Admin-Themes: Django Unfold
Django Unfold ist das aktivste gepflegte Admin-Theme für Django 6, erstellt mit Tailwind CSS. Es erweitert den Standard-Admin anstatt ihn zu ersetzen, sodass bestehende ModelAdmin-Konfigurationen weiterhin funktionieren.
# settings.py
INSTALLED_APPS = [
"unfold", # Must come before django.contrib.admin
"unfold.contrib.filters", # Advanced filter widgets
"unfold.contrib.forms", # Enhanced form widgets
"django.contrib.admin",
# ...
]Unfold fügt Dark Mode, responsive Layouts, Seitenleistennavigation und erweiterte Filtertypen wie RangeNumericFilter und RangeDateFilter hinzu. Die HTMX- und Alpine.js-Integration bietet Interaktivität ohne den Overhead eines vollständigen SPA-Frameworks. Für Teams, die einen polierten Admin ohne den Aufbau eines benutzerdefinierten Dashboards benötigen, spart Unfold Wochen an Frontend-Arbeit.
Fang an zu üben!
Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.
Zusammenfassung zur Django Admin Anpassung
list_displaymit@admin.display()steuert Spalten;orderingfür sortierbare berechnete Werte hinzufügenSimpleListFilterbehandelt benutzerdefinierte Filterlogik, die mehrere Felder umfasst oder Datumsbereiche erfordert- Django 6 Facetten zeigen Filteranzahlen; mit
ShowFacets.NEVERbei großen Tabellen deaktivieren, um COUNT-Abfrage-Overhead zu vermeiden - Admin Actions mit
@admin.action(permissions=[...])behandeln Massenoperationen;HttpResponsefür Dateiexporte zurückgeben list_select_relatedund annotierte Querysets inget_queryset()verwenden, um N+1-Abfragen in Listenansichten zu verhindernRelatedOnlyFieldListFilterverhindert Browser-Einfrieren beim Filtern nach ForeignKey zu großen Tabellen- Diese Muster mit Django-Interviewfragen üben, die speziell auf Admin-Konfiguration abzielen
Findest du den Bug in Django?
Ein echter Codeausschnitt, ein versteckter Bug, ein Versuch pro Tag. Zum Ausprobieren ohne Konto.

Geschrieben von
Anthony Fillion-MailletGründer von SharpSkill
Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.
Aktualisiert am 13. September 2026
Teilen
Verwandte Artikel

Fortgeschrittene Django Middleware 2026: Eigene Middleware, Logging und Interviewfragen
Umfassender Leitfaden zur Django Middleware in 2026: Request-Response-Zyklus, benutzerdefinierte Middleware-Klassen, async-fähige Middleware, Logging-Integration und häufige technische Interviewfragen.

Django Signals vs. Celery Tasks 2026: Wann man was verwendet und Interviewfragen
Erfahren Sie die Unterschiede zwischen Django Signals und Celery Tasks, wann welches Werkzeug eingesetzt wird und häufige Interviewfragen für 2026.

Django Channels 2026: WebSockets, Echtzeit-Kommunikation und Interview-Fragen
Django Channels 4.x Tutorial mit WebSocket-Consumers, Redis Channel Layers und Interview-Fragen für Senior-Entwickler.