Zum Inhalt
Überwachte maschinelle Übersetzung

Dieser Inhalt wurde maschinell übersetzt und basiert auf von Menschen kuratierten Glossaren und Styleguides. Da der Text nicht zeilenweise manuell überprüft wird, können gelegentlich Fehler oder unklare Formulierungen auftreten.

Bei etwaigen Abweichungen ist die ursprüngliche englische Version die maßgebliche Quelle.

Lesen Sie die ursprüngliche englische Version

Ansichten

starlette-admin baut seine Sidebar aus drei Arten von View auf: ModelView stellt ein Datenbankmodell bereit, CustomView rendert eine eigenständige Seite, und Link fügt einen Hyperlink hinzu.

ModelView

Eine ModelView-Unterklasse ist die Art, wie Sie ein Datenbankmodell im Admin bereitstellen. Klassenattribute und Methoden-Overrides dieser View definieren, wie die Ressource aussieht, sich verhält und mit Daten umgeht.

Jedes Beispiel in diesem Abschnitt verwendet das folgende SQLAlchemy-Setup:

from datetime import datetime
from sqlalchemy import DateTime, ForeignKey, String, Text
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship


class Base(DeclarativeBase):
    pass


class Author(Base):
    __tablename__ = "author"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(100))
    books: Mapped[list["Post"]] = relationship(back_populates="author")


class Post(Base):
    __tablename__ = "post"

    id: Mapped[int] = mapped_column(primary_key=True)
    title: Mapped[str] = mapped_column(String(200))
    content: Mapped[str] = mapped_column(Text)
    published: Mapped[bool] = mapped_column(default=False)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
    author_id: Mapped[int] = mapped_column(ForeignKey("author.id"))
    author: Mapped[Author] = relationship(back_populates="books")

Grundlegende Verwendung

Um das Modell Post bereitzustellen, leiten Sie von ModelView ab und konfigurieren dessen Attribute.

from starlette_admin.contrib.sqla import ModelView


class PostView(ModelView):
    fields = ["id", "title", "content", "published", "created_at"]

Eine View-Klasse hat keine Wirkung, bis Sie sie bei einer Admin-Instanz registrieren:

from sqlalchemy import create_engine
from starlette_admin.contrib.sqla import Admin

engine = create_engine("sqlite:///blog.db")
admin = Admin(engine, title="Blog Admin", secret_key="change-me")

# Register the view
admin.add_view(PostView(Post))

Unter examples/01-quickstart finden Sie einen lauffähigen Admin, der auf dieselbe Weise um ein Post-Modell herum aufgebaut wurde.

Durch die Registrierung einer View werden paginierte, sortierbare und durchsuchbare Oberflächen für das Auflisten, Anzeigen, Erstellen, Bearbeiten und Löschen von Datensätzen generiert. Sie müssen weder Routen noch Templates schreiben.

Note

Sie importieren ModelView aus dem contrib-Paket Ihres Backends, etwa starlette_admin.contrib.sqla, .beanie, .mongoengine, .sqlmodel oder .tortoise. Jedes unten beschriebene Attribut ist über alle Backends hinweg identisch, sodass Sie später ein SQLAlchemy-Modell gegen ein MongoEngine-Dokument austauschen können, ohne Ihre View-Logik zu ändern.

Zentrale Konfiguration

Benennung und Routing

Standardmäßig leitet der Admin URL-Routing und UI-Beschriftungen aus dem Klassennamen des Modells ab. Für das Modell Post verwendet er:

  • Key: post (URL: /admin/post/list)
  • Menu label: Posts (Sidebar-Eintrag)
  • Display name: Post (UI-Schaltflächen wie New Post)

Wenn die abgeleiteten Werte nicht passen, überschreiben Sie sie bei der Registrierung oder im Konstruktor.

Attribut Beschreibung Beispiel-Override Resultierende UI oder URL
key Der interne Slug und die Basis-URL-Route. key="blog-post" /admin/blog-post/list
menu_label Der Pluralbegriff, der in der Sidebar verwendet wird. menu_label="Blog Posts" Sidebar: Blog Posts
display_name Der Singularbegriff, der in Aktionen und Formularen verwendet wird. display_name="Article" Buttons: New Article
admin.add_view(
    PostView(Post, key="blog-post", menu_label="Blog Posts", display_name="Article")
)

Feldauswahl und Anpassung

Die Liste fields legt fest, welche Modellattribute in der Listenansicht, auf der Detailseite und in den Formularen erscheinen. Lassen Sie sie weg, um jedes Modellattribut bereitzustellen.

Mischen Sie Zeichenkettennamen mit expliziten BaseField-Instanzen, um Widgets, Validierung und Beschriftungen zu steuern:

from starlette_admin.fields import (
    StringField,
    TextAreaField,
    BooleanField,
    DateTimeField,
)


class PostView(ModelView):
    fields = [
        "id",
        StringField("title", required=True, maxlength=200),
        TextAreaField("content", rows=10),
        BooleanField("published"),
        DateTimeField("created_at", exclude_from_create=True, exclude_from_edit=True),
    ]

Note

Der Admin erkennt den Primärschlüssel automatisch für Sie. Definieren Sie pk_attr nur dann, wenn die Erkennung fehlschlägt, etwa bei einem Custom-Backend ohne Primärschlüssel aus einem einzelnen Feld.

Kontextabhängige Feldsichtbarkeit

Felder gehören oft auf die Liste oder Detailseite, aber nicht in ein Erstellungsformular – etwa Zeitstempel und systemverwaltete Status. Verwenden Sie die Attribute exclude_fields_from_*, um ein Feld auf bestimmten Oberflächen auszublenden:

class PostView(ModelView):
    fields = ["id", "title", "content", "published", "created_at"]

    # Hide from specific surfaces
    exclude_fields_from_create = ["published", "created_at"]
    exclude_fields_from_export = ["content"]

Die verfügbaren Ausschlussattribute enden auf _create, _edit, _list, _detail, _export und _import.

Important

Um Benutzern zu erlauben, den Primärschlüssel beim Erstellen eines Datensatzes selbst festzulegen – standardmäßig deaktiviert –, setzen Sie show_pk_in_forms = True.

Formularlayout

Standardmäßig rendert fields Ihre Erstellungs- und Bearbeitungsformulare als flache, vertikale Liste. Um die Oberfläche umzugestalten, ohne Ihre Datendefinitionen anzufassen, verwenden Sie das Attribut form_layout.

Die Tuple-Kurzschreibweise

Für ein einfaches Raster müssen Sie keine Widget-Klassen importieren. Gruppieren Sie Feldnamen in einem Tuple, um sie nebeneinander in einer Zeile darzustellen.

class ProductView(ModelView):
    fields = ["name", "price", "description"]

    # "name" and "price" share a row; "description" sits below them
    form_layout = [
        ("name", "price"),
        "description",
    ]

Fortgeschrittene Layout-Widgets

Wenn Ihre Formulare wachsen, strukturieren Sie sie mit Layout-Widgets. Die Tuple-Kurzschreibweise funktioniert auch darin:

  • PanelWidget oder FieldsetWidget: Gruppieren Sie verwandte Felder unter einer Überschrift oder machen Sie einen Abschnitt einklappbar.
  • TabsWidget: Trennen Sie klar unterscheidbare Datenkategorien – etwa Versanddetails und SEO-Metadaten –, die nicht gleichzeitig sichtbar sein müssen.
from starlette_admin import TabsWidget


class ProductView(ModelView):
    fields = [
        "name",
        "price",
        "description",
        "sku",
        "weight",
        "shipping_class",
        "meta_title",
        "meta_description",
    ]

    form_layout = [
        TabsWidget(
            tabs=[
                ("Listing", [("name", "price"), "description"]),
                ("Shipping", [("sku", "weight"), "shipping_class"]),
                ("SEO", ["meta_title", "meta_description"]),
            ]
        ),
    ]

Informationen zu mehrspaltigen Zeilen mit expliziten Breiten, Tabs, statischen Inhalten und Zugriffssteuerungsverhalten finden Sie unter Formularlayouts.

Funktionen der Datentabelle

Suche und Sortierung

Steuern Sie mit searchable_fields und sortable_fields, wie Benutzer Daten finden und ordnen.

class PostView(ModelView):
    fields = ["id", "title", "content", "published", "created_at"]
    searchable_fields = ["title", "content"]
    sortable_fields = ["title", "created_at"]
    fields_default_sort = [("created_at", True)]  # Sort newest first
  • searchable_fields: Aktiviert den Filter-Builder und das globale Suchfeld. Die globale Suche führt eine Volltextabfrage über diese Felder aus.
  • sortable_fields: Beschränkt, nach welchen Spaltenüberschriften Benutzer sortieren können. Eine über URL-Parameter übergebene Sortierabfrage für ein anderes Feld wird ignoriert.
  • fields_default_sort: Legt den Anfangszustand der Tabelle fest. Übergeben Sie einen bloßen String für aufsteigende Sortierung, ein Tuple mit True für absteigende Sortierung oder ein Tuple mit False für eine explizit aufsteigende Sortierung. Verketten Sie mehrere Einträge für eine Sortierung über mehrere Spalten.

Paginierung und UI-Steuerelemente

Feinjustieren Sie das Layout der Listenseite mit diesen Attributen:

class PostView(ModelView):
    page_size = 25
    page_size_options = [25, 50, 100, -1]  # -1 renders as "All"
    show_goto_page = True
    search_auto_submit = True
    show_detail_search = True
    row_click_navigate = False
  • page_size und page_size_options: Das Standard-Paginierungslimit und die Auswahlmöglichkeiten im Dropdown.
  • show_goto_page: Fügt ein „Zu Seite springen“-Eingabefeld für große Datenmengen hinzu.
  • search_auto_submit: Filtert bereits während der Eingabe.
  • show_detail_search: Fügt der Detailseite ein Suchfeld hinzu, um eingebettete Beziehungstabellen zu filtern.
  • row_click_navigate: Öffnet die Detailseite, wenn der Benutzer irgendwo in einer Tabellenzeile klickt. Es ist standardmäßig aktiviert. Setzen Sie es auf False, um Zeilen inert zu halten, sodass Benutzer stattdessen über die Zeilenaktionen navigieren. Zeilen sind für Benutzer, deren can_view_detail-Prüfung fehlschlägt, niemals anklickbar.

Inline-Bearbeitung

Sie können Benutzern ermöglichen, bestimmte Felder direkt aus der Listenansicht zu ändern, ohne das vollständige Bearbeitungsformular zu öffnen.

Verwenden Sie das Attribut inline_editable_fields, um zu deklarieren, welche Spalten dies unterstützen. Ein Klick auf eine aktivierte Zelle öffnet dann ein Popover für eine schnelle Aktualisierung.

class PostView(ModelView):
    fields = ["id", "title", "content", "published", "created_at"]

    # Enable quick edits for short text and boolean toggles
    inline_editable_fields = ["title", "published"]

Sicherheit und Zugriff

Inline-Bearbeitung ist standardmäßig deaktiviert. Wenn Sie sie aktivieren, schränkt die bestehende can_edit-Berechtigung der View sie weiterhin ein.

Konfigurationsdetails, Validierungsverhalten und die vollständige Matrix der unterstützten Feldtypen finden Sie in der Anleitung Inline-Bearbeitung.

Relationale Daten

Der Admin übernimmt die Handhabung von Datenbeziehungen für Sie. Für die Many-to-One-Beziehung zwischen Post und Author fügen Sie das Beziehungsattribut zu Ihrer fields-Liste hinzu. Solange beide Modelle registrierte Views haben, rendert die UI die passenden Widgets.

class AuthorView(ModelView):
    fields = ["id", "name", "books"]  # 'books' is a Many relationship


class PostView(ModelView):
    fields = ["id", "title", "author"]  # 'author' is a One relationship


admin.add_view(AuthorView(Author))
admin.add_view(PostView(Post))

Manuelle Deklaration von Beziehungen

Deklarieren Sie HasOne- oder HasMany-Felder selbst nur dann, wenn die Ziel-View unter einem benutzerdefinierten key registriert ist.

from starlette_admin import HasMany, HasOne, StringField


class AuthorView(ModelView):
    fields = ["id", "name", HasMany("books", key="post-article")]


class PostView(ModelView):
    fields = ["id", "title", HasOne("author", key="author")]


# Author uses default key ("author"), Post uses custom key ("post-article")
admin.add_view(AuthorView(Author))
admin.add_view(PostView(Post, key="post-article"))

Objektdarstellung

Wenn der Admin einen Datensatz als einzelnen Wert anzeigen muss, greift er auf den Primärschlüssel zurück. Ein mit Author #3 verknüpfter Post wird dann in Beziehungsspalten als „3“ dargestellt, was dem Benutzer kaum etwas verrät. Zwei optionale Methoden, definiert am Modell statt an der View, ersetzen diesen Standard durch etwas Aussagekräftiges. Beide akzeptieren den aktuellen Request und können synchron oder asynchron sein.

__admin_repr__

Gibt einen einfachen String zurück, der überall dort verwendet wird, wo der Datensatz als Text erscheint: in Beziehungsspalten auf der Listen- und Detailseite, in Breadcrumbs und in Bestätigungsmeldungen von Aktionen.

class Author(Base):
    __tablename__ = "author"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(100))

    def __admin_repr__(self, request: Request) -> str:
        return self.name

Mit dieser Methode wird der Autor eines Posts als „Gabriel Garcia Marquez“ statt als „3“ dargestellt.

__admin_select2_repr__

Gibt ein HTML-Snippet zurück, das die Optionen in den select2-Dropdowns der Beziehungsformularfelder rendert, sodass Sie Auswahlmöglichkeiten mit Bildern, Badges oder ergänzendem Text anreichern können. Ohne diese Methode greift der Admin auf die maskierte Ausgabe von __admin_repr__ zurück. Ohne beide Methoden greift er auf eine automatisch generierte Zusammenfassung der Nicht-Beziehungsfelder des Datensatzes zurück.

from jinja2 import Template


class Author(Base):
    __tablename__ = "author"

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(100))
    avatar_url: Mapped[str] = mapped_column(String(255))

    def __admin_select2_repr__(self, request: Request) -> str:
        template = Template(
            '<div class="d-flex align-items-center">'
            '<span class="avatar me-2" style="background-image: url({{ obj.avatar_url }})"></span>'
            "<span>{{ obj.name }}</span>"
            "</div>",
            autoescape=True,
        )
        return template.render(obj=self)

Note

Der zurückgegebene Wert muss gültiges HTML sein.

Warning

Maskieren Sie Datenbankwerte, um Cross-Site-Scripting-Angriffe (XSS) zu verhindern. Rendern Sie das Snippet mit Jinja2 und autoescape=True, wie oben gezeigt, oder maskieren Sie jeden Wert selbst mit html.escape. Weitere Informationen finden Sie in der OWASP-Dokumentation.

Sicherheit und Autorisierung

Beschränken Sie den Zugriff, indem Sie die Berechtigungsmethoden Ihrer ModelView überschreiben. Jede gibt einen booleschen Wert zurück, und die Basisimplementierungen geben alle True zurück.

Dieses Muster lässt sich direkt in Ihren AuthProvider integrieren. Im folgenden Beispiel liest jede Prüfung eine roles-Liste aus dem admin_user der Session:

from starlette.requests import Request
from starlette_admin.contrib.sqla import ModelView


class PostView(ModelView):
    def is_accessible(self, request: Request) -> bool:
        # If this returns False, the view is entirely hidden from the UI
        return any(":post" in role for role in request.state.admin_user.roles)

    def can_create(self, request: Request) -> bool:
        return "create:post" in request.state.admin_user.roles

    def can_edit(self, request: Request) -> bool:
        return "edit:post" in request.state.admin_user.roles

    def can_delete(self, request: Request) -> bool:
        return "delete:post" in request.state.admin_user.roles

    def can_view_detail(self, request: Request) -> bool:
        return "read:post" in request.state.admin_user.roles

Weitere Informationen zur Konfiguration Ihres AuthProvider und zum Befüllen des admin_user-Objekts finden Sie unter Authentifizierung.

Note

Überschreiben Sie nur die Methoden, die Sie einschränken möchten. Die übrigen gewähren weiterhin Zugriff.

Lifecycle-Hooks

Verwenden Sie Lifecycle-Hooks, um Seiteneffekte auszuführen oder Daten unmittelbar vor oder nach einer Datenbanktransaktion zu verändern.

from typing import Any
from starlette.requests import Request


class PostView(ModelView):
    async def before_create(
        self, request: Request, data: dict[str, Any], obj: Any
    ) -> None:
        # Mutate the object before it hits the database
        obj.title = obj.title.strip()

    async def after_create(self, request: Request, obj: Any) -> None:
        # Trigger post-creation side effects
        print(f"Created post #{obj.id}")

Die verfügbaren Hooks sind before_create, after_create, after_create_committed, before_edit, after_edit, after_edit_committed, before_delete, after_delete und after_delete_committed.

Committed-Hooks

after_create_committed, after_edit_committed und after_delete_committed werden erst ausgeführt, nachdem die Datenbanktransaktion committet wurde. Verwenden Sie sie für Seiteneffekte, die bei einem Rollback eines Schreibvorgangs nicht stattfinden dürfen – etwa den Versand von E-Mails oder das Einreihen von Hintergrundjobs:

class PostView(ModelView):
    async def after_create_committed(self, request: Request, obj: Any) -> None:
        await send_new_post_notification(obj.id)

Warning

Zu dem Zeitpunkt, an dem diese Hooks ausgeführt werden, ist die Session der Anfrage bereits committed und geschlossen. Schreiben Sie innerhalb dieser Hooks nicht über request.state.session in die Datenbank. Nutzen Sie externe I/O oder öffnen Sie eine neue Datenbank-Session.

Important

In after_delete_committed ist obj von jeder Session detached. Vor dem Löschen geladene Attribute bleiben lesbar, aber das Lesen eines nie geladenen Attributs schlägt fehl, da die Zeile nicht mehr existiert.

Unterstützung durch Backends

Nur Backends, die den Commit bis zum Ende der Anfrage verzögern, emittieren diese Hooks. Derzeit ist das das SQLAlchemy-Backend.

Tip

Für Logik, die sich über mehrere Views erstreckt – etwa ein Audit-Log –, verwenden Sie stattdessen Events.

UI-Anpassung

Gruppieren Sie verwandte Views mit DropDown in einem einklappbaren Ordner. Ein Ordner kann ModelView-, CustomView- und Link-Einträge mischen.

from starlette_admin import DropDown, Link

admin.add_view(
    DropDown(
        "Content Management",
        icon="fa fa-folder",
        views=[
            PostView(Post, icon="fa fa-newspaper"),
            AuthorView(Author, icon="fa fa-user"),
            Link(
                menu_label="View Live Site",
                icon="fa fa-external-link",
                url="/",
                target="_blank",
            ),
        ],
    )
)

Exporter und Importer

Die Attribute exporters und importers legen fest, welche Formate für den Datentransfer verfügbar sind. Informationen zu den integrierten Optionen und zum Schreiben eigener Implementierungen finden Sie in der Anleitung Export & Import.

class PostView(ModelView):
    exporters = ["csv", "xlsx"]
    importers = ["json"]

Aktionen, Inline-Formulare und Templates

ModelView bietet drei weitere Funktionsgruppen für komplexe Fälle, jeweils mit eigener Anleitung:

  • Aktionen und Zeilenaktionen: Die Attribute actions und row_actions fügen benutzerdefinierte Batch- und zeilenweise Operationen jenseits von CRUD hinzu. Siehe Aktionen.
  • Inline-Formulare: Das Attribut inlines bettet die Erstellungs- und Bearbeitungsformulare eines verwandten Modells in die übergeordnete View ein. Siehe Inline-Formulare.
  • Templates und Assets: Ersetzen Sie die Standardseiten durch Ihre eigenen Jinja-Templates über list_template, detail_template, create_template oder edit_template. Siehe Templates.

CustomView

Nicht jede Admin-Seite lässt sich auf ein Datenbankmodell abbilden. CustomView erstellt eine eigenständige Sidebar-Seite auf Basis von Widgets, eigenen Templates oder eigenen Routen.

from starlette_admin import CustomView, StatWidget

admin.add_view(
    CustomView(
        menu_label="System Status",
        icon="fa fa-heart-pulse",
        path="/status",
        widget=StatWidget(title="Pending jobs", value_callback=count_pending_jobs),
    )
)

Informationen zum vollständigen Widget-Katalog, zu Dashboard-Anleitungen und zu eigenen Routen finden Sie unter Eigene Views.

Link fügt der Sidebar einen Hyperlink hinzu, der Benutzer zu einer Live-Site, externen Dokumentation oder einem anderen internen Tool führt.

from starlette_admin import Link

admin.add_link(
    Link(
        menu_label="View Live Site",
        icon="fa fa-external-link",
        url="/",
        target="_blank",
    )
)
  • label und icon: Der Text und das Icon des Sidebar-Eintrags.
  • url und target: Das Ziel und das Zielattribut des Ankers.

admin.add_link(link) ist ein schlanker Wrapper um admin.add_view(link). Verwenden Sie, was in Ihrer Codebase besser lesbar ist. Sie können einen Link auch in ein DropDown verschachteln, wie unter Organisation der Sidebar gezeigt.


Nächste Schritte

  • Felder: Der vollständige Katalog der Feldtypen.
  • Formularlayouts: Arrangieren Sie Erstellungs- und Bearbeitungsformulare mit Zeilen, Panels, Fieldsets und Tabs.
  • Eigene Views: Erstellen Sie Dashboards und eigenständige Seiten mit Widgets, Templates und eigenen Routen.
  • Aktionen & Zeilenaktionen: Fügen Sie Batch- und zeilenweise Operationen jenseits von CRUD hinzu.
  • Inline-Bearbeitung: Ermöglichen Sie Benutzern, ein einzelnes Feld einer Zeile direkt auf der Listenseite zu bearbeiten.
  • Inline-Formulare: Betten Sie die Erstellungs- und Bearbeitungsformulare eines verwandten Modells in eine übergeordnete View ein.
  • Templates: Tauschen Sie die Jinja-Templates gegen eigene aus und binden Sie eigene Assets ein.