List view — Pagination, sorting, search and filters
The admin list works at SQL level: pagination, sort, search and filters. Nothing is loaded into memory just to page.
The admin list works at SQL level: pagination, sort, search and filters. Nothing is loaded into memory just to page.
Config is declared on ModelAdmin via .list(|l| …).
Displayed columns
.list(|l| l.display([Title, Status, Views]))
Without display, every non-secret column appears (accounts: username, email, is_active), with dates and times last. A declared display keeps its order. A row's detail page follows that order, but always puts dates and times at the end.
Array order is header order.
Detail links
.list(|l| l.display([Title, Status]).links([Title]))
No effect for now: links is accepted and checked (its columns must be in display), but the list shows each row as a card with its own link to the detail (and its menu), whatever the declared columns.
Sorting
Default SQL order:
.list(|l| {
l.display([Title, CreatedAt])
.ordering([(CreatedAt, Order::Desc), (Title, Order::Asc)])
})
Clickable sort from the UI / URL — only declared columns:
.sortable([Title, Status])
Any other ?sort_by= is ignored.
Search
.list(|l| l.search([Title, Summary]))
Behaviour:
- minimum 3 characters (shorter terms are ignored)
- beyond the staging's
.search_max_len(n)(150 by default), the term is truncated - without
.search(...): text columns fromdisplayare used .search([])disables the search.search_help("…")is accepted but not shown yet
Filters
.list(|l| l.filter([Status, Lang]))
Each filter offers distinct values in the allowed scope, page by page. URL prefix is filter_:
?filter_status=Published&filter_status=Draft&filter_lang=en
Several values of one column add up (Published or Draft), several columns combine (and). Clicking a value turns it on; clicking it again turns it off, the others stay. A column accepts at most 100 values from the URL.
Each group of the panel has its arrows, and a single selector, under the panel's title, sets the number of values of all groups:
| Level | Method | Default |
|---|---|---|
| Site | AdminStaging::filter_size(n) | 10 |
| Model | ListConfig::filter_size(n) | inherits site |
admin.filter_size(8)
.list(|l| l.filter([PageId]).filter_size(15))
The choice made in the selector (10, 25, 50 or 100) wins over these settings.
Bulk actions
.list(|l| {
l.display([Title, Status])
.action(Status, "Published", "Publish")
.action(Status, "Archived", "Archive")
})
The UI sends the action index (a0, a1…), never the raw value. The value is fixed in code.
Boot constraints:
- column writable on edit
- no secret, no owner, no account rank flags
Pagination
| Level | Method | Default |
|---|---|---|
| Site | AdminStaging::page_size(n) | 10 |
| Model | ListConfig::per_page(n) | inherits site |
admin.page_size(15)
.list(|l| l.per_page(30))
The list's selector (10, 25, 50 or 100) wins over these settings. The URL can't ask for another size.
URL parameters
| Param | Role |
|---|---|
page | Page number (1-based) |
sort_by | Column name (must be in sortable) |
sort_dir | asc or desc |
search | Full-text term |
per_page | Rows per page (10, 25, 50 or 100) |
filter_<col> | Filter value, repeatable |
fpage_<col> | Page of values of the filter group <col> |
fsize | Values per page of the filter groups (10, 25, 50 or 100) |
Example:
/admin/blog/list?page=2&sort_by=title&sort_dir=asc&search=runique&filter_status=Published
Empty value
.list(|l| l.empty_value("—"))
No effect for now: accepted, but the list doesn't use this text yet.