Anpassen der Django-Admin-Site

Beginner

Einführung

Dieser Tutorial beginnt dort, wo Add a Stylesheet and an Image aufgehört hat. Wir setzen die Web-Umfrageanwendung fort und werden uns auf die Anpassung der automatisch generierten Django-Admin-Site konzentrieren, die wir zuerst in Set Up the Database untersucht haben.

Anpassen des Admin-Formulars

Durch die Registrierung des Question-Modells mit admin.site.register(Question) konnte Django eine Standardformdarstellung erstellen. Oft möchten Sie anpassen, wie das Admin-Formular aussieht und funktioniert. Sie tun dies, indem Sie Django die Optionen mitteilen, die Sie möchten, wenn Sie das Objekt registrieren.

Schauen wir, wie dies funktioniert, indem wir die Felder im Bearbeitungsformular neu anordnen. Ersetzen Sie die Zeile admin.site.register(Question) durch:

Bearbeiten Sie die Datei ~/project/mysite/polls/admin.py, so dass sie wie folgt aussieht:

from django.contrib import admin

from.models import Question


class QuestionAdmin(admin.ModelAdmin):
    fields = ["pub_date", "question_text"]


admin.site.register(Question, QuestionAdmin)

Sie werden dieses Muster befolgen - erstellen Sie eine ModelAdmin-Klasse und übergeben Sie sie als zweites Argument an admin.site.register() - jedes Mal, wenn Sie die Admin-Optionen für ein Modell ändern müssen.

Starten Sie den Django-Entwicklungsserver:

cd ~/project/mysite
python manage.py runserver

Öffnen Sie http://127.0.0.1:8000/admin/ in Firefox des Desktop-Umgebungs und klicken Sie auf den Link "Fragen". Sie sollten ein Formular sehen, das wie folgt aussieht.

Dieser spezifische Änderung oben bewirkt, dass das "Veröffentlichungsdatum" vor dem Feld "Frage" erscheint:

Admin form field reorder

Dies ist mit nur zwei Feldern nicht beeindruckend, aber für Admin-Formulare mit mehreren Dutzend Feldern ist die Auswahl einer intuitiven Reihenfolge ein wichtiger Usability-Detail.

Und wenn es um Formulare mit mehreren Dutzend Feldern geht, möchten Sie vielleicht das Formular in Feldergruppen unterteilen:

from django.contrib import admin

from.models import Question


class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {"fields": ["question_text"]}),
        ("Date information", {"fields": ["pub_date"]}),
    ]


admin.site.register(Question, QuestionAdmin)

Das erste Element jedes Tuples in ~django.contrib.admin.ModelAdmin.fieldsets ist der Titel der Feldgruppe. So sieht unser Formular jetzt aus:

Admin form with fieldsets

Hinzufügen von verknüpften Objekten

Okay, wir haben unsere Frage-Admin-Seite, aber eine Frage hat mehrere Wahlmöglichkeiten, und die Admin-Seite zeigt die Wahlmöglichkeiten nicht an.

Noch nicht.

Es gibt zwei Möglichkeiten, dieses Problem zu lösen. Die erste besteht darin, Wahlmöglichkeit wie bei Frage bei der Admin zu registrieren:

from django.contrib import admin

from.models import Choice, Question

#...
admin.site.register(Choice)

Jetzt ist "Wahlmöglichkeiten" eine verfügbare Option im Django-Admin. Das Formular "Wahlmöglichkeit hinzufügen" sieht so aus:

Add Choice form interface

In diesem Formular ist das Feld "Frage" ein Auswahlkästchen, das jede Frage in der Datenbank enthält. Django weiß, dass eine ~django.db.models.ForeignKey im Admin als <select>-Kästchen dargestellt werden sollte. Im Moment existiert hier nur eine Frage.

Beachten Sie auch den Link "Eine weitere Frage hinzufügen" neben "Frage". Jedes Objekt mit einer ForeignKey-Beziehung zu einem anderen bekommt diesen kostenlos. Wenn Sie auf "Eine weitere Frage hinzufügen" klicken, erhalten Sie ein Popup-Fenster mit dem Formular "Frage hinzufügen". Wenn Sie in diesem Fenster eine Frage hinzufügen und auf "Speichern" klicken, speichert Django die Frage in der Datenbank und fügt sie dynamisch als ausgewählte Wahlmöglichkeit auf dem Formular "Wahlmöglichkeit hinzufügen" hinzu, das Sie betrachten.

Allerdings ist dies auf Dauer eine ineffiziente Weise, Wahlmöglichkeit-Objekte zum System hinzuzufügen. Es wäre besser, wenn Sie eine Reihe von Wahlmöglichkeiten direkt hinzufügen könnten, wenn Sie das Frage-Objekt erstellen. Machen wir das möglich.

Entfernen Sie den register()-Aufruf für das Wahlmöglichkeit-Modell. Anschließend bearbeiten Sie den Registrierungs-Code für Frage wie folgt:

from django.contrib import admin

from.models import Choice, Question


class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3


class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {"fields": ["question_text"]}),
        ("Date information", {"fields": ["pub_date"], "classes": ["collapse"]}),
    ]
    inlines = [ChoiceInline]


admin.site.register(Question, QuestionAdmin)

Dies sagt Django: "Wahlmöglichkeit-Objekte werden auf der Frage-Admin-Seite bearbeitet. Standardmäßig werden genug Felder für 3 Wahlmöglichkeiten bereitgestellt."

Laden Sie die Seite "Frage hinzufügen", um zu sehen, wie das aussieht:

Question admin with choices

Es funktioniert so: Es gibt drei Plätze für verknüpfte Wahlmöglichkeiten - wie durch extra angegeben - und jedes Mal, wenn Sie zur "Ändern"-Seite für ein bereits erstelltes Objekt zurückkehren, erhalten Sie weitere drei zusätzliche Plätze.

Am Ende der drei aktuellen Plätze finden Sie einen Link "Eine weitere Wahlmöglichkeit hinzufügen". Wenn Sie darauf klicken, wird ein neuer Platz hinzugefügt. Wenn Sie den hinzugefügten Platz entfernen möchten, können Sie auf das X oben rechts im hinzugefügten Platz klicken. Dieses Bild zeigt einen hinzugefügten Platz:

Additional slot added dynamically

Es gibt jedoch ein kleines Problem. Es benötigt viel Bildschirmplatz, um alle Felder für das Eingeben von verknüpften Wahlmöglichkeit-Objekten anzuzeigen. Aus diesem Grund bietet Django eine tabellarische Möglichkeit, inline-verknüpfte Objekte anzuzeigen. Um sie zu verwenden, ändern Sie die ChoiceInline-Deklaration wie folgt:

class ChoiceInline(admin.TabularInline):
 ...

Mit dieser TabularInline (anstelle von StackedInline) werden die verknüpften Objekte in einem kompakteren, tabellenbasierten Format angezeigt:

Tabular inline choices display

Beachten Sie, dass es eine zusätzliche Spalte "Löschen?" gibt, die es ermöglicht, Zeilen zu entfernen, die mit der Schaltfläche "Eine weitere Wahlmöglichkeit hinzufügen" hinzugefügt wurden, sowie Zeilen, die bereits gespeichert wurden.

Anpassen der Admin-Änderungsliste

Jetzt, da die Frage-Admin-Seite gut aussieht, machen wir einige Anpassungen an der "Änderungsliste"-Seite - der Seite, die alle Fragen im System anzeigt.

So sieht sie derzeit aus:

Polls change list page

Standardmäßig zeigt Django die str() jedes Objekts. Manchmal wäre es jedoch hilfreicher, wenn wir einzelne Felder anzeigen könnten. Um das zu tun, verwenden Sie die ~django.contrib.admin.ModelAdmin.list_display-Admin-Option, die ein Tupel von Feldnamen ist, die als Spalten auf der Änderungsliste-Seite für das Objekt angezeigt werden sollen:

class QuestionAdmin(admin.ModelAdmin):
    #...
    list_display = ["question_text", "pub_date"]

Als zusätzliche Verbesserung fügen wir auch die was_published_recently()-Methode aus Set Up the Database hinzu:

class QuestionAdmin(admin.ModelAdmin):
    #...
    list_display = ["question_text", "pub_date", "was_published_recently"]

Jetzt sieht die Frage-Änderungsliste-Seite so aus:

Question change list view

Sie können auf die Spaltenüberschriften klicken, um nach diesen Werten zu sortieren - Ausnahme: die Spaltenüberschrift von was_published_recently, da das Sortieren nach der Ausgabe einer beliebigen Methode nicht unterstützt wird. Beachten Sie auch, dass die Spaltenüberschrift von was_published_recently standardmäßig der Name der Methode ist (mit Unterstrichen durch Leerzeichen ersetzt) und dass jede Zeile die Zeichenfolge-Darstellung der Ausgabe enthält.

Sie können dies verbessern, indem Sie den ~django.contrib.admin.display-Decorator auf diese Methode (in polls/models.py) anwenden, wie folgt:

from django.contrib import admin


class Question(models.Model):
    #...
    @admin.display(
        boolean=True,
        ordering="pub_date",
        description="Published recently?",
    )
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now

Weitere Informationen zu den über den Decorator konfigurierbaren Eigenschaften finden Sie in ~django.contrib.admin.ModelAdmin.list_display.

Bearbeiten Sie Ihre polls/admin.py-Datei erneut und fügen Sie eine Verbesserung zur Frage-Änderungsliste-Seite hinzu: Filter mit ~django.contrib.admin.ModelAdmin.list_filter. Fügen Sie der QuestionAdmin die folgende Zeile hinzu:

list_filter = ["pub_date"]

Das fügt eine "Filter"-Leiste hinzu, mit der Benutzer die Änderungsliste nach dem pub_date-Feld filtern können:

Admin list filter sidebar

Der angezeigte Filtertyp hängt vom Typ des zu filternden Felds ab. Da pub_date ein ~django.db.models.DateTimeField ist, weiß Django, passende Filteroptionen anzuzeigen: "Jede beliebige Date", "Heute", "Letzte 7 Tage", "Dieser Monat", "Dieses Jahr".

Das sieht gut aus. Fügen wir noch eine Suchfunktion hinzu:

search_fields = ["question_text"]

Das fügt eine Suchleiste oben auf der Änderungsliste hinzu. Wenn jemand Suchbegriffe eingibt, sucht Django im question_text-Feld. Sie können so viele Felder wie Sie möchten verwenden - obwohl es hinter den Kulissen eine LIKE-Abfrage verwendet, wird es für Ihre Datenbank einfacher, die Suche zu erledigen, wenn Sie die Anzahl der Suchfelder auf eine vernünftige Zahl begrenzen.

Es ist auch ein guter Zeitpunkt, zu beachten, dass Änderungslisten Ihnen eine kostenlose Seitenaufteilung bieten. Der Standardwert ist es, 100 Elemente pro Seite anzuzeigen. Änderungslisten-Seitenaufteilung <django.contrib.admin.ModelAdmin.list_per_page>, Suchfelder <django.contrib.admin.ModelAdmin.search_fields>, Filter <django.contrib.admin.ModelAdmin.list_filter>, Datumshierarchien <django.contrib.admin.ModelAdmin.date_hierarchy> und Spaltenüberschriften-Sortierung <django.contrib.admin.ModelAdmin.list_display> funktionieren alle zusammen, wie Sie es erwarten würden.

Anpassen des Admin-Aussehens und der Bedienbarkeit

Offensichtlich ist es lächerlich, "Django-Verwaltung" oben auf jeder Admin-Seite zu haben. Es ist nur Platzhaltertext.

Sie können es jedoch ändern, indem Sie das Django-Templatesystem verwenden. Die Django-Admin wird von Django selbst betrieben, und ihre Schnittstellen verwenden das eigene Templatesystem von Django.

Anpassen der Projekt -Templates

Erstellen Sie ein Verzeichnis templates im Projektverzeichnis (dem Verzeichnis, das manage.py enthält). Templates können an jedem Ort auf der Dateisystemebene gespeichert werden, auf den Django zugreifen kann. (Django läuft als der Benutzer, unter dem auch der Server läuft.) Es ist jedoch eine gute Konvention, die Templates innerhalb des Projekts zu halten.

Öffnen Sie Ihre Einstellungsdatei (mysite/settings.py, denken Sie daran) und fügen Sie eine DIRS <TEMPLATES-DIRS> -Option in die TEMPLATES -Einstellung hinzu:

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / "templates"],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

DIRS <TEMPLATES-DIRS> ist eine Liste von Dateisystemverzeichnissen, die überprüft werden, wenn Django-Templates geladen werden; es ist ein Suchpfad.

Organisieren von Templates

Genau wie die statischen Dateien könnten wir alle unsere Templates zusammen in einem großen templates -Verzeichnis haben, und es würde perfekt funktionieren. Allerdings sollten Templates, die zu einer bestimmten Anwendung gehören, in das Templateverzeichnis dieser Anwendung (z.B. polls/templates) statt im Projektverzeichnis (templates) platziert werden. Wir werden im reusable apps tutorial </intro/reusable-apps> im Detail diskutieren, warum wir dies tun.

Erstellen Sie nun ein Verzeichnis namens admin innerhalb von templates, und kopieren Sie die Vorlage admin/base_site.html aus dem Standard-Django-Admin-Templateverzeichnis im Quellcode von Django selbst (django/contrib/admin/templates) in dieses Verzeichnis.

Wo befinden sich die Django-Quelldateien?

Wenn Sie Schwierigkeiten haben, zu finden, wo sich die Django-Quelldateien auf Ihrem System befinden, führen Sie den folgenden Befehl aus:

python -c "import django; print(django.__path__)"
['/home/labex/.local/lib/python3.10/site-packages/django']

Anschließend bearbeiten Sie die Datei und ersetzen Sie {{ site_header|default:_('Django administration') }} (einschließlich der geschweiften Klammern) durch den Namen Ihrer eigenen Website, wie Ihnen am besten passt. Sie sollten am Ende mit einem Codeabschnitt wie diesem übrigbleiben:

{% block branding %}
<div id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a><div>
{% endblock %}

Wir verwenden diese Methode, um Ihnen zu zeigen, wie Sie Templates überschreiben. In einem tatsächlichen Projekt würden Sie wahrscheinlich das Attribut django.contrib.admin.AdminSite.site_header verwenden, um diese spezifische Anpassung einfacher vorzunehmen.

Diese Template-Datei enthält viel Text wie {% block branding %} und {{ title }}. Die Tags {% und {{ sind Teil der Django-Templatelanguage. Wenn Django admin/base_site.html rendert, wird diese Templatelanguage ausgewertet, um die endgültige HTML-Seite zu erzeugen, genauso wie wir es in **Creating the Public Interface Views** gesehen haben.

Beachten Sie, dass jeder der Standard-Django-Admin-Templates überschrieben werden kann. Um ein Template zu überschreiben, tun Sie das Gleiche wie mit base_site.html - kopieren Sie es aus dem Standardverzeichnis in Ihr benutzerdefiniertes Verzeichnis und machen Sie Änderungen.

Anpassen der Anwendung -Templates

Genau beobachtende Leser werden fragen: Aber wenn DIRS <TEMPLATES-DIRS> standardmäßig leer war, wie hat Django die Standard-Admin-Templates gefunden? Die Antwort ist, dass, da APP_DIRS <TEMPLATES-APP_DIRS> auf True gesetzt ist, Django automatisch nach einem templates/ -Unterverzeichnis innerhalb jedes Anwendungs-Pakets sucht, um es als Rückfall zu verwenden (vergessen Sie nicht, dass django.contrib.admin eine Anwendung ist).

Unsere Umfrageanwendung ist nicht sehr komplex und benötigt keine benutzerdefinierten Admin-Templates. Wenn sie jedoch komplexer würde und Änderungen an den Standard-Django-Admin-Templates für einige ihrer Funktionen erforderte, wäre es vernünftiger, die Anwendung -Templates zu modifizieren, anstatt die im Projekt. Auf diese Weise könnten Sie die Umfrageanwendung in jedes neue Projekt einbetten und sicherstellen, dass sie die benötigten benutzerdefinierten Templates finden würde.

Siehe die template loading documentation <template-loading> für weitere Informationen darüber, wie Django seine Templates findet.

Anpassen der Admin-Startseite

In ähnlicher Weise möchten Sie vielleicht das Aussehen und die Bedienbarkeit der Django-Admin-Startseite anpassen.

Standardmäßig werden alle Apps in INSTALLED_APPS, die mit der Admin-Anwendung registriert wurden, in alphabetischer Reihenfolge angezeigt. Möglicherweise möchten Sie erhebliche Änderungen am Layout vornehmen. Schließlich ist die Startseite wahrscheinlich die wichtigste Seite der Admin und sollte einfach zu bedienen sein.

Das zu customisierende Template ist admin/index.html. (Tun Sie das Gleiche wie mit admin/base_site.html im vorherigen Abschnitt - kopieren Sie es aus dem Standardverzeichnis in Ihr benutzerdefiniertes Templateverzeichnis). Bearbeiten Sie die Datei, und Sie werden sehen, dass sie eine Template-Variable namens app_list verwendet. Diese Variable enthält jede installierte Django-App. Anstatt dies zu verwenden, können Sie Links zu objekt-spezifischen Admin-Seiten in der Weise hartcodieren, die Ihnen am besten erscheint.

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das Lab "Anpassen der Django-Admin-Site" abgeschlossen. Sie können in LabEx weitere Labs absolvieren, um Ihre Fähigkeiten zu verbessern.