Die Administrationsoberfläche ausbauen
Wir wollen die Event-Verwaltung noch ein bisschen ausbauen. Die erste Änderung soll eine kleine Schönheitskorrektur auf der Event-Detailseite sein. Aktuell kann man die Kategorie des Events in einem Drop-Down-Feld auswählen. Wir wollen dies ändern und aus dem Drop-Down-Feld ein Reihe von Radio-Buttons machen, die horizontal angeordnet sind.
Zusätzlich wollen wir das Min-Group-Feld als vertikal angeordnete Radio-Group anlegen.
Admin Actions
Nun möchten wir auf der Events-Übersicht mehrere
Events markieren und alle auf einen Schlag inaktiv setzen können.
Bisher gibt es im Aktion
-Dropdown nur eine Aktion: ausgewählte Events löschen
.
Wollten wir aber ausgewählte Events nicht löschen, sondern nur auf aktiv bzw.
inaktiv stellen, müssen wir jedes Event anklicken und auf der Eventseite
die is_active
-Eigenschaft ändern. Das ist mühselig, wenn man
das bei mehreren Events machen möchte. Dafür gibt es sogenannte Actions
.
Wir fügen nun diese beiden Methoden hier in usere EventAdmin
-Klasse ein:
@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
# ... mehr Code
list_filter = ("category",)
list_display = "date", "slug", "author", "name", "category"
actions = ["make_active", "make_inactive"]
@admin.action(description="Setze Events active")
def make_active(self, request, queryset):
"""Set all Events to active."""
queryset.update(is_active=True)
@admin.action(description="Setze Events inactive")
def make_inactive(self, request, queryset):
"""Set all Events to inactive."""
queryset.update(is_active=False)
Der @admin.action
-Decorator ist optional und macht nichts
weiter, als der Aktion in dem Aktionen-Dropdown-Feld einen greifbaren
Namen zu geben. Interessant sind jetzt die beiden Methoden
make_active
bzw. make_inactive
.
Diese beiden Methoden unserer EventAdmin
-Klasse haben den
Parameter queryset
. Dieses queryset entspricht den auswählten
also markierteren Events in der Eventübersicht. Führt man nun
eine Aktion aus, bekommt die jeweilige Methode diese Events als
queryset übergeben und wir können jetzt eine Aktion auf jeden dieser
Events ausführen.
make_active
zum Beispiel setzt die is_active
Eigenschaft auf
true und aktiviert damit die ausgewählten Events. Der @admin.action
-Dekorator
setzt noch die Eigenschaft description
auf einen sprechenden Namen.
@admin.action(description="Setze Events active")
def make_active(self, request, queryset):
"""Set all Events to active."""
queryset.update(is_active=True)
Damit diese beiden Methoden jetzt in der Admin auch registriert sind,
müssen wir die Methoden-Referenzen an die actions
-Liste übergeben.
actions = ["make_active", "make_inactive"]
Mehr zu AdminActions gibt es in der Django-Doku: https://docs.djangoproject.com/en/4.1/ref/contrib/admin/actions/
Den Kategorie-Slug in der Event-Übersicht darstellen
Bisher zeigen wir nur die Kategorie in der Eventübesicht an. Wir wollen
die Ansicht aber erweitern, und den Slug der Category
auch noch
darstellen.
Leider funktioniert der Zugriff via category__slug
in der list_display
-Eigenschaft
nicht. Es kommt zu einem Fehler
@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
# ... mehr Code
list_display = ("date", "slug", "author", "name", "category", "category__slug")
Um das Problem zu umgehen, schreiben wir uns eine eigene Methode,
dekorieren sie mit dem @admin.display
-Dekorator und nutzen
den Methoden-Namen in list_display
, um die Spalte anzuzeigen.
@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
# mehr Code
list_display = ("date",
"slug",
"author",
"name",
"category",
"category_slug")
@admin.display(description="Kategorie Slug")
def category_slug(self, obj):
return obj.category.slug
Wir können problemlos eigene Methoden in der EventAdmin
-Klasse definieren,
und diese als Felder in der Übersicht unserer Events darstellen.
Das übergebene obj
ist im Fall von category_slug
das Event-Objekt selbst.
Read Only Felder
Falls wir Felder in der Administrationsoberfläche readonly
haben möchten,
d.h., dass sie zumindest über die Admin nicht mehr geändert werden können,
gibt es das Attribut readonly_fields
. Wir wollen, dass der Autor eines
Events nachträglich nicht mehr geändert werden kann und fügen folgendes in die
Klasse ein:
readonly_fields = ("author",)
Damit sind alle Felder des Tuples auf readonly.
Die fertige EventAdmin
-Klasse sieht jetzt so aus:
@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("name",)}
list_display = (
"date",
"slug",
"author",
"name",
"category",
"category_slug",
)
list_filter = ("category",)
search_fields = ["name"]
actions = ["make_active", "make_inactive"]
# date_hierachy = "date"
readonly_fields = ("author",)
list_display_links = ("name", "slug")
radio_fields = {
"category": admin.HORIZONTAL,
"min_group": admin.VERTICAL,
}
@admin.action(description="Setze Events active")
def make_active(self, request, queryset):
"""Set all Entries to active."""
queryset.update(active=True)
@admin.action(description="Setze Events inactive")
def make_inactive(self, request, queryset):
"""Set all Entries to inactive."""
queryset.update(active=False)
@admin.display(description="Kategorie Slug")
def category_slug(self, obj):
return obj.category.slug