Aller au contenu
Traduction automatique supervisée

Ce contenu est traduit à l'aide d'une génération automatique guidée par des glossaires et des guides de style élaborés par des humains. Le texte n'étant pas relu manuellement ligne par ligne, des erreurs ou des tournures maladroites peuvent occasionnellement apparaître.

En cas de divergence, la version anglaise constitue la source de référence.

Lire la version originale en anglais

Templates

Chaque page de l'admin est un template Jinja2 que vous pouvez remplacer. Modifiez une seule page de liste, la cellule d'un champ dans le tableau, ou un widget du dashboard sans dupliquer l'arborescence des templates intégrés.

Fonctionnement du loader de templates

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

engine = create_engine("sqlite:///admin.sqlite")
admin = Admin(engine, title="My Admin", templates_dir="my_templates/")

Admin construit un ChoiceLoader Jinja2 qui interroge d'abord votre templates_dir, puis le répertoire intégré du package starlette_admin/templates/. Placez un fichier sous my_templates/ au même chemin relatif qu'il occupe dans starlette_admin/templates/ et votre fichier masquera celui intégré. Tous les autres templates continuent d'être rendus depuis le répertoire intégré.

Note

La chaîne de loaders enregistre également un PrefixLoader sous la clé @starlette-admin, qui pointe toujours vers les templates intégrés, quels que soient les fichiers qui les masquent dans templates_dir. Accédez-y avec le format de chemin @starlette-admin/<name>.html, sans barre oblique finale sur le préfixe lui-même. Consultez Remplacer le template d'une seule page ci-dessous pour connaître son utilité.

Cartographie des répertoires de templates

Chemin Utilisé pour
base.html Mise en page HTML externe (<html>, <head>, scripts)
layout.html Habillage de la sidebar et de la barre supérieure (étend base.html)
index.html Dashboard ou page d'accueil
list.html Page de liste d'un modèle (tableau, barre de filtres, pagination)
detail.html Vue détaillée (en lecture seule) d'un enregistrement
create.html Formulaire de création
edit.html Formulaire d'édition
login.html Page de connexion
error.html Page d'erreur HTTP (403, 404, etc.)
actions.html Fenêtre modale d'action groupée
row-actions.html Menu déroulant d'actions par ligne
inline.html Formset en ligne sur les pages de création/édition
inline_detail.html Tableau en ligne sur la page de détail
inline_row.html Ligne unique dans un formset en ligne
_filter_bar.html Barre des filtres actifs au-dessus de la liste
_filter_builder.html Fenêtre modale du constructeur de filtres
_pagination.html Contrôles de pagination
_column_header.html Cellule d'en-tête de colonne triable
_form_footer.html Boutons Enregistrer, Enregistrer et continuer, ou Ajouter un autre
_form_group.html Fieldset d'un groupe de mise en page de formulaire sur le formulaire de création/édition
_form_group_fields.html Les champs affichés à l'intérieur d'un groupe de mise en page de formulaire
fields/list/<type>.html Cellule de colonne pour un type de champ
fields/detail/<type>.html Affichage sur la page de détail pour un type de champ
fields/form/<type>.html Widget de saisie de formulaire pour un type de champ
widgets/<name>.html Template de widget du dashboard
modals/actions.html Fenêtre modale de confirmation d'action
modals/delete.html Fenêtre modale de confirmation de suppression
modals/error.html Fenêtre modale d'erreur
modals/import.html Fenêtre modale d'importation
macros/views.html Macros Jinja2 partagées utilisées dans plusieurs pages

Note

L'arborescence intégrée contient aussi modals/loading.html, une fenêtre modale générique d'état de chargement, ainsi que plusieurs templates spécifiques aux champs dans fields/list/, fields/detail/ et fields/form/. Vérifiez les noms de fichiers exacts dans starlette_admin/templates/ pour la version installée avant de remplacer un fichier <type>.html générique.

Remplacer le template d'une seule page

my_templates/
└── list.html   ← remplace le list.html intégré
{# my_templates/list.html #}
{% extends "@starlette-admin/list.html" %}

{% block content %}
  <div class="alert alert-info">Bannière personnalisée au-dessus de la liste.</div>
  {{ super() }}
{% endblock %}

{% extends "list.html" %} résoudrait vers votre propre my_templates/list.html, car templates_dir est interrogé en premier, et cette référence circulaire provoque une erreur de récursion infinie. Le préfixe @starlette-admin/ pointe toujours vers la copie intégrée : chaque extends et include dans un fichier de remplacement doit donc l'utiliser plutôt que le nom de fichier seul.

Blocs remplaçables

Chaque page intégrée étend layout.html, qui étend lui-même base.html. Remplacez un seul {% block %} plutôt qu'un fichier entier pour modifier un fragment sans dupliquer le reste de la page :

{# my_templates/list.html #}
{% extends "@starlette-admin/list.html" %}

{% block list_toolbar_extra %}
  {{ super() }}
  <a class="btn btn-outline-primary" href="/reports/export">Rapport personnalisé</a>
{% endblock %}

base.html

Bloc Contenu
favicon La balise <link> du favicon
title La balise <title>
head_meta Les balises <meta> à l'intérieur de l'élément <head>
head_css Les balises <link> des feuilles de style
head Un point d'insertion libre dans l'élément <head>
body Tout le contenu de <body> (ce bloc est remplacé par layout.html)
modal Un point d'insertion au niveau de la page pour les fenêtres modales
script Les balises <script> situées juste avant la balise fermante </body>
tail Un point d'insertion vide tout à la fin de <body>, après script

layout.html

Bloc Contenu
sidebar L'intégralité de l'élément <aside> de la sidebar (y compris le logo, le menu et le pied de page)
brand L'image du logo (ou le repli app_title) dans le lien de marque de la sidebar
sidebar_menu La liste des liens de vues dans la sidebar
sidebar_footer La zone basse de la sidebar
user_menu_trigger L'avatar et le nom d'utilisateur affichés sur le bouton du menu utilisateur. Défini une seule fois et réutilisé à la fois sur la sidebar mobile et la navbar de bureau via self.user_menu_trigger(), si bien que le remplacer met à jour les deux
user_menu_items Les éléments déroulants du menu utilisateur
navbar La barre de navigation supérieure
navbar_extra Du contenu supplémentaire placé dans la navbar à côté du menu utilisateur
header La zone d'en-tête de la page positionnée au-dessus de content (inclut le titre et le fil d'Ariane)
flash_messages La zone dédiée à l'affichage des messages flash
content_before Un point d'insertion immédiatement avant content
content Le contenu principal de la page (c'est le bloc alimenté par list.html, detail.html, etc.)
content_after Un point d'insertion immédiatement après content
page_footer La zone de pied de page située sous le contenu de la page

list.html

Bloc Contenu
header L'en-tête de la page (inclut le titre et le fil d'Ariane)
page_title Le titre <h1> à l'intérieur de l'en-tête
breadcrumbs Le fil d'Ariane à l'intérieur de l'en-tête
modal Les fenêtres modales de suppression, d'action et d'importation
content Le corps complet de la page de liste
list_search La zone de saisie de recherche
list_toolbar La rangée d'outils contenant les boutons de filtres, d'export, d'import et de création
list_toolbar_extra Un point d'insertion supplémentaire tout à la fin de la barre d'outils
list_before_table Un point d'insertion avant le tableau
list_table L'élément <table> lui-même
list_header La ligne <thead> contenant la case à cocher et les cellules d'en-tête de colonnes
list_row Une seule ligne <tr> du tableau de résultats (bloc à portée ; donne accès à row, row_pk et row_clickable)
list_row_actions_before La cellule des actions de ligne lorsque row_actions_position vaut BEFORE_COLUMNS (bloc à portée)
list_row_actions_after La cellule des actions de ligne lorsque row_actions_position vaut AFTER_COLUMNS (bloc à portée)
list_empty Le texte indicatif « No data » (bloc à portée rendu pour les états vides)
list_after_table Un point d'insertion après le tableau
list_footer Le pied de page de pagination et de plage
head_css Ajouts de feuilles de style propres à la page
script Ajouts de scripts propres à la page

detail.html

Bloc Contenu
header L'en-tête de la page (inclut le titre, le fil d'Ariane et les actions)
page_title Le titre <h1> à l'intérieur de l'en-tête
breadcrumbs Le fil d'Ariane à l'intérieur de l'en-tête
modal Les fenêtres modales de suppression et d'action
content Le corps complet de la page de détail
detail_before Un point d'insertion avant la carte de détail
detail_title La zone de titre à l'intérieur de la carte de détail
detail_actions Les boutons d'action à l'intérieur de la carte de détail
details_table Le tableau principal des champs et valeurs
detail_after Un point d'insertion après la carte de détail
head_css Ajouts de feuilles de style propres à la page
script Ajouts de scripts propres à la page

create.html / edit.html

Bloc Contenu
header L'en-tête de la page (inclut le titre et le fil d'Ariane)
page_title Le titre <h1> à l'intérieur de l'en-tête
breadcrumbs Le fil d'Ariane à l'intérieur de l'en-tête
content Le corps complet de la page du formulaire
form_before Un point d'insertion avant la carte du formulaire
create_card_header / edit_card_header La zone d'en-tête à l'intérieur de la carte du formulaire
create_form / edit_form Les groupes de mise en page de formulaire (chacun rendu via _form_group.html) et leurs éléments de saisie de champs
create_inlines / edit_inlines La zone du formset en ligne
form_footer Les boutons Enregistrer, Enregistrer et continuer, et Ajouter un autre
form_after Un point d'insertion après la carte du formulaire
head_css Ajouts de feuilles de style propres à la page
script Ajouts de scripts propres à la page

login.html

Bloc Contenu
header / sidebar Laissés vides (la page de connexion masque l'habillage standard de l'application)
content Le corps complet de la page de connexion
login_logo Le logo affiché au-dessus du formulaire de connexion
login_title Le texte du titre de la page de connexion
login_form_before Un point d'insertion avant les champs du formulaire
login_fields Les champs de saisie du nom d'utilisateur et du mot de passe
login_form_footer Un point d'insertion après les champs mais à l'intérieur du formulaire
login_card_footer Un point d'insertion situé directement sous la carte de connexion
script Ajouts de scripts propres à la page

index.html

Bloc Contenu
head_css Ajouts de feuilles de style propres aux widgets
content La grille de widgets du dashboard
script Ajouts de scripts propres aux widgets

error.html

Bloc Contenu
header / sidebar Laissés vides (la page d'erreur masque l'habillage standard de l'application)
content Le message d'erreur et les actions associées
error_actions Boutons d'action affichés sous le message d'erreur (comme un bouton « Retour »)

Tip

Appelez {{ super() }} dans un fichier de remplacement pour conserver le contenu du bloc intégré et y ajouter du contenu plutôt que de le remplacer. L'exemple list_toolbar_extra ci-dessus procède ainsi, et les fichiers intégrés index.html et create.html utilisent le même motif pour le bloc head_css.

Exemple : remplacer le logo de la sidebar par un SVG en ligne

Passer une URL à Admin(logo_url=...) est le moyen le plus rapide de définir un logo et couvre la plupart des cas, y compris les fichiers .svg externes. Cependant, le template intégré affiche cette URL dans une balise <img>, si bien que le SVG ne peut pas hériter des propriétés CSS de la page environnante.

Remplacez le bloc brand avec du balisage <svg> en ligne lorsque vous avez besoin que le logo réponde au reste de l'interface.

Implémentation

Créez un fichier layout.html dans votre répertoire de templates. Chaque page de l'admin hérite de layout.html, ce remplacement s'applique donc à l'ensemble du site.

{# my_templates/layout.html #}
{% extends "@starlette-admin/layout.html" %}

{% block brand %}
  <svg class="navbar-logo" viewBox="0 0 32 32" fill="currentColor">
    <path d="M16 2 L30 9 L30 23 L16 30 L2 23 L2 9 Z" />
  </svg>
{% endblock %}

Conservez la classe navbar-logo

Gardez la classe CSS navbar-logo sur votre élément <svg> personnalisé. Elle confère à votre graphique en ligne l'alignement, le padding et le dimensionnement du framework sans aucun CSS de votre part.

Remplacer les templates de champs

Le contexte de chaque champ utilise trois sous-répertoires :

Répertoire Utilisé dans
fields/list/<type>.html Cellule du tableau de liste (compacte, lecture seule)
fields/detail/<type>.html Affichage sur la page de détail (complet, lecture seule)
fields/form/<type>.html Champ de saisie des formulaires de création et d'édition

Vous pouvez remplacer la cellule de liste pour les champs textuels sans toucher au formulaire ni à l'affichage détaillé :

my_templates/
└── fields/
    └── list/
        └── text.html

Pour pointer une instance de champ précise vers votre template au lieu de remplacer le type partout, définissez list_template, detail_template, form_template, null_template ou empty_template directement sur le champ :

from starlette_admin.fields import StringField

StringField("status", list_template="fields/list/status_badge.html")

null_template (par défaut "fields/detail/_null.html") et empty_template (par défaut "fields/detail/_empty.html") sont des emplacements distincts. Les pages de liste et de détail les affichent à la place de list_template ou detail_template chaque fois que la valeur du champ est None ou une liste ou un tuple vide :

StringField("status", null_template="fields/detail/_status_null.html")

Remplacer les templates de widgets

Les widgets suivent le même motif de remplacement. Placez vos fichiers sous le répertoire widgets/ :

my_templates/
└── widgets/
    └── stat_widget.html

Variables globales de template

Ces variables sont disponibles dans chaque template sans avoir à être passées explicitement. Admin les installe comme variables globales Jinja2 une seule fois lors de la configuration :

Variable Type Description
views list[BaseView] Toutes les vues enregistrées (utilisées pour rendre la sidebar)
app_title str Le titre de l'admin (Admin(title=...))
is_auth_enabled bool True si un fournisseur d'authentification est configuré
__name__ str Le préfixe de nom de route de l'admin (par exemple, "admin")
static_url callable static_url(request, path, v=None) → URL d'une ressource statique intégrée. L'argument v ajoute un paramètre de requête anti-cache ?v=.
logo_url callable logo_url(request) → URL du logo de la sidebar, ou None si non défini
login_logo_url callable login_logo_url(request) → URL du logo de la page de connexion, ou None si non défini
favicon_url callable favicon_url(request) → URL du favicon, ou None si non défini
list_url callable list_url(request, **overrides) → URL avec overrides fusionnés dans sa chaîne de requête (utilisé pour les liens de tri, de pagination ou de recherche). Passez None pour supprimer une clé.
detail_url callable detail_url(request, key, pk) → URL de la page de détail d'un enregistrement
edit_url callable edit_url(request, key, pk) → URL de la page d'édition d'un enregistrement
export_url callable export_url(request, key, fmt) → URL de téléchargement d'export reprenant l'état de filtrage/tri/recherche de la page de liste courante
import_url callable import_url(request, key) → URL POST d'importation
get_locale callable get_locale() → Chaîne de la locale active (ne nécessite pas d'argument request)
get_locale_display_name callable get_locale_display_name(locale) → Nom lisible d'une chaîne de locale
i18n_config I18nConfig Objet de configuration i18n de l'admin
get_timezone callable get_timezone() → Chaîne du fuseau horaire actif (ne nécessite pas d'argument request)
get_timezone_display_name callable get_timezone_display_name(timezone, show_offset=False) → Nom lisible d'une chaîne de fuseau horaire
timezone_config TimezoneConfig | None Configuration du fuseau horaire de l'admin
theme_settings TablerSettings Configuration active du thème Tabler (base, primary, radius, mode) exposée par DefaultTheme
csrf_input callable csrf_input(request) → Rend le champ <input> CSRF caché

Note

get_locale, get_locale_display_name, get_timezone et get_timezone_display_name ne prennent pas de paramètre request. Ils lisent la locale et le fuseau horaire depuis des contextvars que LocaleMiddleware renseigne pendant toute la durée de la requête, plutôt que depuis l'objet Request.

Variables de contexte par page

En plus des variables globales ci-dessus, chaque page transmet son propre dictionnaire de contexte à TemplateResponse.

list.html

Variable Type Description
view BaseModelView La vue courante
title str Titre de la page
fields list[BaseField] Colonnes actuellement visibles
all_fields list[BaseField] Tous les champs de liste (y compris ceux cachés)
rows list[dict] Données de lignes sérialisées
total int Nombre total d'enregistrements correspondants pour la pagination
total_pages int Nombre total de pages
range_start int Numéro du premier enregistrement de cette page (à partir de 1)
range_end int Numéro du dernier enregistrement de cette page
list_params ListParams État d'URL analysé (page, page_size, q, sorts, filters)
filter_logic str | None Vaut "and" ou "or" pour le groupe de filtres actif de premier niveau
filter_chips list Descripteurs des puces de filtres actives
filter_builder_fields list Champs disponibles dans l'interface du constructeur de filtres
raw_filter str | None Chaîne JSON brute du filtre provenant de l'URL
_actions list Actions groupées disponibles
row_actions dict[Any, list] Actions de ligne disponibles par enregistrement, indexées par pk

detail.html

Variable Type Description
view BaseModelView La vue courante
title str Titre de la page
obj dict Enregistrement sérialisé
raw_obj Any L'objet modèle brut avant sérialisation
inlines list[dict] Contexte en ligne ([{"inline": InlineModelView, "rows": [...]}])
_actions list Actions de ligne disponibles

create.html / edit.html

Variable Type Description
view BaseModelView La vue courante
title str Titre de la page
obj dict Valeurs actuelles des champs (valeurs par défaut à la création, valeurs existantes à l'édition)
raw_obj Any Objet modèle brut (édition uniquement, absent à la création)
errors dict[str, list[str]] Erreurs de validation indexées par nom de champ (présent uniquement après une soumission échouée)
inlines list[dict] Contexte du formset en ligne

Ajouter vos propres globals et filtres

Pour ajouter vos propres variables et fonctions aux templates, créez une sous-classe d'Admin et redéfinissez __init__. Appelez d'abord super().__init__(), afin que self.templates existe avant que vous ne le complétiez :

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


class MyAdmin(Admin):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.templates.env.globals["site_name"] = "My App"
        self.templates.env.filters["currency"] = lambda v: f"${v:,.2f}"


engine = create_engine("sqlite:///admin.sqlite")
admin = MyAdmin(engine, title="My Admin")

Filtres Jinja2 intégrés

Chaque instance de l'admin enregistre ces filtres durant _setup_templates :

Filtre Signature Description
is_custom_view view | is_custom_view Renvoie True si la ressource est une CustomView
is_link view | is_link Renvoie True si la ressource est une Link
is_model_view view | is_model_view Renvoie True si la ressource est une BaseModelView
is_dropdown view | is_dropdown Renvoie True si la ressource est une DropDown
tojson value | tojson Sérialisation JSON sûre pour HTML (remplace le tojson par défaut de Jinja2)
file_icon mime_type | file_icon Renvoie une classe d'icône complète pour un type MIME (par exemple, application/pdffa-solid fa-fw fa-file-pdf) ; redéfinissez self.templates.env.filters["file_icon"] pour utiliser votre propre jeu d'icônes
to_view key | to_view Recherche une BaseModelView enregistrée à partir de sa clé ; lève une HTTPException 404 si introuvable
is_iter value | is_iter Renvoie True si la valeur est une list ou un tuple
is_str value | is_str Renvoie True si la valeur est une str
is_dict value | is_dict Renvoie True si la valeur est un dict
ra value | ra Convertit une chaîne en membre de l'énumération RequestAction
safe_url url | safe_url Renvoie l'URL uniquement si elle passe la vérification d'URL sûre, sinon renvoie ""
sanitize_html html | sanitize_html Supprime les balises non autorisées d'une chaîne HTML et renvoie une Markup

Pour aller plus loin

  • Mises en page de formulaire : Divisez les formulaires de création et d'édition en groupes titrés, éventuellement repliables, et remplacez _form_group.html pour modifier leur balisage.
  • Thèmes personnalisés : Redonnez du style à l'admin sans toucher aux templates individuels.
  • Champs personnalisés : Associez la classe Python d'un champ à son propre list_template ou form_template.
  • Points d'extension : La liste complète des surfaces extensibles au-delà des templates.