Builder `ModelAdmin`
API typée pour déclarer la liste et le formulaire d'un modèle. Les colonnes sont des variantes d'enum SeaORM (Column::Title) : une faute de frappe ne compile pas.
Squelette
fn articles() -> ModelAdmin<article::Entity> {
use article::Column::*;
ModelAdmin::new()
.title("Articles")
.list(|l| {
l.display([Title, Status, Views])
.links([Title])
.sortable([Title, Status])
.ordering([(Title, Order::Asc)])
.search([Title, Summary])
.search_help("Titre ou résumé")
.filter([Status])
.per_page(15)
.empty_value("—")
.action(Status, "Published", "Publier")
.action(Status, "Archived", "Archiver")
})
.form(|f| {
f.fields([Title, Summary, Body, Status, Views])
.readonly([Views])
.create_only([Title])
.labels([(Summary, "Résumé"), (Body, "Contenu")])
})
}
Le use …::Column::* reste dans la fonction du modèle : deux modèles avec une colonne Title ne se marchent jamais dessus.
Méthodes de `ModelAdmin`
| Méthode | Rôle |
|---|---|
.title("…") | Nom dans la nav et les pages (sinon verbose_name_plural, verbose_name, puis le nom de table) |
.list(…) | Configure la vue liste |
.form(…) | Configure create / edit |
.templates(…) | Surcharge des blocs ou des pages de ce modèle (HTML, CSS), voir Surcharge |
Liste — `ListConfig`
| Méthode | Effet |
|---|---|
.display([Col, …]) | Colonnes visibles, dans l'ordre |
.links([Col, …]) | Colonnes cliquables vers le détail. Sans effet pour l'instant (voir Limites) : chaque ligne a son lien vers le détail |
.sortable([Col, …]) | Seules colonnes acceptées via ?sort_by= |
.ordering([(Col, Order::Asc), …]) | Tri SQL par défaut |
.search([Col, …]) | Colonnes plein-texte. Sans appel : textes du display. .search([]) désactive |
.search_help("…") | Texte d'aide de la recherche. Sans effet pour l'instant (voir Limites) |
.filter([Col, …]) | Filtres latéraux (?filter_status=…) |
.per_page(n) | Taille de page pour ce modèle |
.filter_size(n) | Valeurs par page des groupes de filtre pour ce modèle |
.empty_value("—") | Texte des valeurs vides. Sans effet pour l'instant (voir Limites) |
.action(Col, value, "Label") | Action groupée : fixe Col à value sur les lignes cochées |
Actions groupées
.list(|l| {
l.display([Title, Status])
.action(Status, "Published", "Publier")
.action(Status, "Archived", "Archiver")
})
Règles au boot :
- la colonne d'action doit être writable à l'édition (dans
fields, pasreadonly/create_only) - interdites sur les secrets, le owner, et les drapeaux de rang comptes (
is_superuser,is_dirigeant,is_admin,is_active)
Formulaire — `FormConfig`
| Méthode | Effet |
|---|---|
.fields([Col, …]) | Champs affichés, dans l'ordre |
.readonly([Col, …]) | Visibles mais non modifiables |
.create_only([Col, …]) | Saisissables à la création, figés ensuite |
.labels([(Col, "Libellé"), …]) | Libellés custom |
.form(|f| {
f.fields([Slug, Title, Body, ViewCount])
.create_only([Slug])
.readonly([ViewCount])
.labels([(ViewCount, "Vues")])
})
Sans .form(), tous les champs du formulaire du modèle (ModelMeta::Form) sont utilisés. La porte décide encore ce que le compte courant peut lire ou écrire.
Comptes étendus
Pour exposer les colonnes ajoutées par extend! sur eihwaz_users :
fn accounts() -> ModelAdmin<user_profile::Entity> {
use user_profile::Column::*;
ModelAdmin::new()
.list(|l| {
l.display([Username, Email, IsActive, Website])
.search([Username, Email])
})
.form(|f| f.fields([Username, Email, Bio, Website, Phone]))
}
// dans site() :
site.accounts_users(accounts())
Les drapeaux de rang (is_superuser, is_dirigeant, is_admin) ne sont pas des champs du formulaire. Le boot les refuse. Le rang se change depuis la fiche du compte. write::insert refuse un Set(true) sur ces colonnes, write::update refuse tout Set. is_superuser se pose avec runique create-superuser. Détail : Permissions.
Secrets
Les colonnes marquées secrètes sur le modèle (mot de passe, tokens…) sont refusées dans display, search, filter, sortable, links, fields, actions. Le message d'erreur apparaît au validate() de boot.
Limites actuelles
.links,.search_helpet.empty_valuesont acceptés et vérifiés au démarrage, mais l'affichage de la liste ne les utilise pas encore : la liste montre chaque ligne en carte avec son lien vers le détail, sans texte d'aide sous la recherche, et les valeurs vides telles quelles.
Exemple réel (demo-app)
fn blog() -> ModelAdmin<blog::Entity> {
use blog::Column::*;
ModelAdmin::new()
.list(|l| {
l.display([Title, Email, Website, Status])
.links([Title])
.sortable([Title, Status])
.ordering([(Title, Order::Asc)])
.search([Title, Summary])
.filter([Status])
.empty_value("—")
.action(Status, "Published", "Publier")
.action(Status, "Archived", "Archiver")
})
.form(|f| {
f.fields([Title, Email, Website, Summary, Content, Status, ViewCount])
.readonly([ViewCount])
})
}