.. _admin_app: .. index:: single: admin single: Administrationsoberfläche 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 Mingroups in einem Drop-Down-Feld auswählen. Wir wollen dies ändern und aus dem Drop-Down-Feld ein Reihe von Radio-Buttons machen, die vertikal angeordnet sind. Choice-Felder als Radio Buttons in der Admin darstellen ====================================================================== Wir öffnen die Datei ``event_manager/events/admin.py`` und modifizieren das ``EventAdmin``-Klasse: .. code-block:: python @admin.register(Event) class EventAdmin(admin.ModelAdmin): # anderer Code radio_fields = { "min_group": admin.VERTICAL, } Die Eigenschaft ``radio_fields`` der ModelAdmin-Klasse ermöglicht uns komfortabel das Ändern der Eigenschaft: .. image:: /images/admin_5_min_group.png 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``. .. image:: /images/admin_6_actions.png 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: .. code-block:: python @admin.register(Event) class EventAdmin(admin.ModelAdmin): # ... mehr Code list_filter = ("category",) list_display = "date", "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. .. code-block:: python @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. .. code-block:: python actions = ["make_active", "make_inactive"] Mehr zu AdminActions gibt es in der Django-Doku: ``_ 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: .. code-block:: python readonly_fields = ("author",) Damit sind alle Felder des Tuples auf readonly. Die fertige ``EventAdmin``-Klasse sieht jetzt so aus: .. code-block:: python @admin.register(Event) class EventAdmin(admin.ModelAdmin): list_display = ( "date", "author", "name", "category", ) list_display_links = ("name",) list_filter = ("category",) search_fields = ["name"] actions = ["make_active", "make_inactive"] readonly_fields = ("author",) 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) Fachmethoden in der Liste angeben =================================== Bisher hatten wir in ``list_display`` nur gewöhnliche Felder angezeigt, zum Beispiel Name oder Autor. Was ist aber, wenn wir zum Beispiel für das Kategoriemodell in der Übersicht auch die Anzahl der Events anzeigen wollten? Das ``Category`` - Model besitzt die methode ``num_of_events``, welche wir im Zusammenhang mit Formularen für das Model angelegt hatten. Diese Methode liefert die Events einer Kategorie. Wir erinnern uns: .. code-block:: python class Category(DateMixin): """Eine Kategorie für einen Event.""" name = models.CharField(max_length=100, unique=True) sub_title = models.CharField(max_length=200, null=True, blank=True) description = models.TextField(null=True, blank=True) class Meta: ordering = ["name"] def __str__(self): return self.name def num_of_events(self): """Die Anzahl der Events einer Kategorie.""" return self.events.count() Wir können diese Methode in ``list_display`` im Admin-Model genauso angeben, wie jedes beliebige andere Feld. Passen wir also die Klasse ``CategoryAdmin`` an: .. code-block:: python @admin.register(Category) class CategoryAdmin(admin.ModelAdmin): list_display = "id", "name", "sub_title", "num_of_events" list_display_links = ("name", "sub_title") list_filter = ("events", "sub_title") search_fields = ["name"] .. image:: /images/category_admin_events.png Queryset überschreiben =================================== Auf die Adminoberfläche haben alle User Zugriff, die den Staff-Status gesetzt haben. Wir könnten zum Beispiel implementieren, dass Adminuser, d.h. User mit dem Superuser-Status alle Events sehen können, alle anderen, zum Beispiel Moderatoren, nur eigene Events. Dafür lässt sich die Methode ``get_queryset()`` überschreiben. .. code-block:: python def get_queryset(self, request): """Only superusers can see all events.""" qs = super().get_queryset(request) if request.user.is_superuser: return qs return qs.filter(author=request.user) Die Django-Adminoberfläche bietet noch vieles mehr, was angepasst werden und verändert werden kann. Das soll nur ein kurzer Einblick sein, was man mit relativ wenig Aufwand anpassen kann. eine neue Djangoadmin Oberfläche =================================== Wer eine schönere Djangoadmin-Oberfläche ohne viel Arbeit haben möchte, sollte sich mal `Grapelli `_ ansehen. Damit lassen sich mit einfachen Mitteln deutliche Verbesserungen in der Optik erzielen.