Options catalog
Every Chassis capability is a frozen dataclass. You do not subclass a
mixin for search, another for badges, and another for export. You append
option objects to ModelAdmin.options or assign site-level options on
ChassisAdminSiteMixin.
This page is the full catalog: purpose, fields, defaults, validation, and which UI region each option drives.
How lookup works
ChassisAdminMixin.get_chassis_option(option_class=...) returns the first
instance of that type on the local options list. If the local list has no
match, it falls back to ChassisAdminMixin.options, which is
[RowActionsOption()].
Consequences:
- At most one instance of each option type is used. Put several FK tab groups
inside one
ForeignKeyTabsOption, not as three sibling options. - If you set
options = [SearchOption(...)]and omitRowActionsOption, the mixin still injects the default view button from the class-level list. - To hide row actions, pass
RowActionsOption(actions=[]). Settingsis not anAdminOption. Assign it tochassis_settings.
Do not rename the options attribute.
AdminOption union
These types are legal on ModelAdmin.options:
| Option | Page region |
|---|---|
SearchOption | Changelist search fieldset |
FiltersOption | Changelist filter fieldset |
DateHierarchyOption | Changelist date drill-down |
FieldTabsOption | Changelist choice tabs |
ForeignKeyTabsOption | Changelist FK tabs |
BadgeFieldsOption | Changelist badge columns |
PrettyJsonOption | Change form / list JSON |
DecimalAmountOption | Integer money as Decimal |
RowActionsOption | Last changelist column |
ListActionsOption | Changelist toolbar |
ObjectActionsOption | Change-form toolbar |
RelatedEntitiesOption | Change-form related tables |
ImportOption | Import flow + toolbar button |
ExportOption | Export flow + toolbar button |
Nested types (RowActionOption, TableColumnOption, …) are not
AdminOption members. They live inside a parent option.
Site-level types (Sidebar*, AdminPageGroupOption, PermissionOption)
are assigned on the AdminSite, not on options.
Settings
Not an option. Assigned to chassis_settings on a ModelAdmin or AdminPage.
from django_chassis.options import Settings
chassis_settings = Settings(
search_collapsed=True, date_hierarchy_collapsed=True, filters_collapsed=True, allow_standard_add=True
)
| Field | Type | Default | Effect |
|---|---|---|---|
search_collapsed | bool | True | Search fieldset starts collapsed |
date_hierarchy_collapsed | bool | True | Date hierarchy starts collapsed |
filters_collapsed | bool | True | Filters fieldset starts collapsed |
allow_standard_add | bool | True | Show Django's Add button in the changelist toolbar |
allow_standard_add=False makes has_add_permission() return False, so
the standard Add button disappears. List actions and import/export buttons
are unaffected.
SearchOption
Puts Django search_fields into a Chassis fieldset above the result table.
The mixin writes search_fields onto the instance so Django's own
checks still see them.
from django_chassis.options import SearchOption
SearchOption(fields=['title', 'isbn', 'author__name'], fieldset_title='Search', placeholder='Title, ISBN, or author')
| Field | Type | Default | Required |
|---|---|---|---|
fields | list[str] | — | yes |
fieldset_title | str or gettext lazy | _('Поиск') | no |
placeholder | str or gettext lazy | '' | no |
fields uses Django search lookups (icontains by default, ^ prefix,
= exact, @ full text — same as stock Admin).
Without this option the changelist has no search fieldset.
FiltersOption
Renders Chassis select-filters in their own fieldset. fields is assigned
to Django list_filter.
from django.contrib.admin import SimpleListFilter
from django_chassis.options import FiltersOption
FiltersOption(fields=['status', 'author', PublishedThisYearFilter], fieldset_title='Filters')
| Field | Type | Default | Required |
|---|---|---|---|
fields | list[Any] | — | yes |
fieldset_title | localized string | _('Фильтры') | no |
Accepted values are the same as Django list_filter: field names, related
lookups, and SimpleListFilter subclasses.
The stock Django right-hand filter sidebar is suppressed
({% block filters %}{% endblock %}). Filters live in the Chassis controls
stack above the table.
DateHierarchyOption
Enables Django date_hierarchy and wraps it in a Chassis fieldset.
from django_chassis.options import DateHierarchyOption
DateHierarchyOption(field='published_at', fieldset_title='Dates')
| Field | Type | Default | Required |
|---|---|---|---|
field | str | — | yes — DateField / DateTimeField name |
fieldset_title | localized string | _('Даты') | no |
The mixin writes date_hierarchy on the instance for Django checks.
FieldTabsOption
Tabs (or a <select>) that filter the changelist by a choices field on
the current model. Each tab is a query-string link; "All" clears the filter.
from django_chassis.enums import TabDisplay
from django_chassis.options import FieldTabsOption
FieldTabsOption(
field='status', choices=Book.Status.choices, display=TabDisplay.BUTTONS, all_label='All', fieldset_title='Status'
)
| Field | Type | Default | Required |
|---|---|---|---|
field | str | — | yes |
choices | list[tuple[Any, Any]] | — | yes — (value, label) pairs |
display | TabDisplay | TabDisplay.BUTTONS | no |
all_label | localized string | _('Все') | no |
fieldset_title | localized string | _('Tabs') | no |
TabDisplay.BUTTONS renders a row of links. TabDisplay.SELECT renders a
dropdown that navigates on change.
Use this when the dimension is a local choices field. Use
ForeignKeyTabsOption when the dimension is a related model.
ForeignKeyTabsOption
One or more tab groups, each bound to a ForeignKey on the current model. Every related object that appears in the queryset becomes a tab.
from django_chassis.options import ForeignKeyTabGroupOption, ForeignKeyTabsOption
ForeignKeyTabsOption(
groups=[
ForeignKeyTabGroupOption(field='author', model=Author, label='Authors', all_label='All authors'),
ForeignKeyTabGroupOption(field='publisher', model=Publisher, label='Publishers'),
],
display=TabDisplay.BUTTONS,
fieldset_title='Relations',
)
Single-group shortcut
ForeignKeyTabsOption(field='author', model=Author)
is equivalent to one ForeignKeyTabGroupOption in groups.
| Field | Type | Default | Required |
|---|---|---|---|
groups | list[ForeignKeyTabGroupOption] | [] | one of groups or field+model |
field | str or None | None | shortcut |
model | model class or None | None | shortcut |
display | TabDisplay | BUTTONS | no |
all_label | localized string | _('Все') | no |
fieldset_title | localized string | _('Tabs') | no |
ForeignKeyTabGroupOption
| Field | Type | Default | Required |
|---|---|---|---|
field | FK field name on the current model | — | yes |
model | related model class | — | yes |
label | localized string | '' | no — group heading |
all_label | localized string | _('Все') | no |
You cannot attach two ForeignKeyTabsOption objects. Put every group in
groups.
BadgeFieldsOption
Renders named changelist columns as colored badges. The mixin replaces each
listed field in list_display with a generated display method.
from django_chassis.enums import ButtonColor
from django_chassis.options import BadgeFieldsOption
BadgeFieldsOption(
fields=['status', 'kind'],
colors={'status': {'active': ButtonColor.SUCCESS, 'draft': ButtonColor.SECONDARY, 'archived': ButtonColor.WARNING}},
)
| Field | Type | Default | Required |
|---|---|---|---|
fields | list[str] | — | yes |
colors | Mapping[str, Mapping[object, ButtonColor]] | {} | no |
A missing color mapping uses the default badge tone. Keys of the inner mapping are the raw field values (enum members, strings, booleans).
ButtonColor: primary, secondary, success, warning, danger,
info.
PrettyJsonOption
Builds a read-only pretty_<field> display method for each JSON field and
highlights it with Pygments. Domain ModelAdmins do not declare those methods
by hand.
from django_chassis.options import PrettyJsonOption
PrettyJsonOption(fields=['payload', 'metadata'])
| Field | Type | Default | Required |
|---|---|---|---|
fields | list[str] | — | yes |
Put the original field name in list_display / readonly_fields if you
want the pretty column on the changelist or change form. The mixin installs
the method at __init__ time.
DecimalAmountOption
Displays integer minor-unit amounts as Decimal using two methods on the model:
_get_fraction_number(...)convert_amount_to_decimal(...)
If either method is missing, the option is silently ignored (no column
rewrite). If a listed name is not an IntegerField, construction raises
ImproperlyConfigured.
from django_chassis.options import DecimalAmountOption
DecimalAmountOption(fields=['amount', 'fee'])
| Field | Type | Default | Required |
|---|---|---|---|
fields | list[str] | — | yes — unique integer field names |
Duplicate names raise ValueError('Chassis decimal amount field names must be unique.').
Generated list-display name: chassis_decimal_<field>. Sorting still uses
the underlying integer.
RowActionsOption / RowActionOption
Last changelist column. The first column is not a change-link unless
you set chassis_link_first_column = True.
Default without arguments: one view button (Открыть / Open,
fa-solid fa-arrow-right, ButtonColor.PRIMARY, icon display).
from django_chassis.enums import ButtonColor, RowActionDisplay, RowActionType
from django_chassis.options import RowActionOption, RowActionsOption
RowActionsOption(
actions=[
RowActionOption(
action_type=RowActionType.VIEW,
label='Open',
color=ButtonColor.PRIMARY,
icon_class='fa-solid fa-arrow-right',
display=RowActionDisplay.ICON,
),
RowActionOption(
action_type=RowActionType.CHANGE,
label='Edit',
color=ButtonColor.SECONDARY,
icon_class='fa-solid fa-pen',
permission='change',
),
RowActionOption(
action_type=RowActionType.DELETE,
label='Delete',
color=ButtonColor.DANGER,
icon_class='fa-solid fa-trash',
permission='delete',
),
RowActionOption(
action_type=RowActionType.HISTORY,
label='History',
color=ButtonColor.SECONDARY,
icon_class='fa-solid fa-clock-rotate-left',
),
]
)
RowActionsOption
| Field | Type | Default |
|---|---|---|
actions | list[RowActionOption] | one VIEW action |
RowActionOption
| Field | Type | Default | Required |
|---|---|---|---|
action_type | RowActionType | — | yes — view, change, delete, history |
label | localized string | — | yes |
color | ButtonColor | — | yes |
icon_class | Font Awesome class | — | yes |
display | RowActionDisplay | ICON | no — icon or button |
permission | str or None | None | no — inferred from type when possible |
A failed permission hides the button. There is no disabled placeholder.
ListActionsOption / ListActionOption
Toolbar links above the changelist (next to Add and import/export). They resolve a Django URL name; they do not run ModelAdmin methods.
from django_chassis.options import ListActionOption, ListActionsOption
ListActionsOption(
actions=[
ListActionOption(
url_name='admin:catalog_book_changelist',
label='All books',
color=ButtonColor.PRIMARY,
icon_class='fa-solid fa-list',
permission='view',
condition_method='can_show_all_books',
)
]
)
ListActionOption
| Field | Type | Default | Required |
|---|---|---|---|
url_name | Django URL name | — | yes |
label | localized string | — | yes |
color | ButtonColor | PRIMARY | no |
icon_class | Font Awesome class | '' | no |
permission | codename or None | None (treated as view in checks) | no |
condition_method | method name or None | None | no |
condition_method must be a @classmethod shaped (cls, request) -> bool.
False omits the action. A missing or non-classmethod name fails at
ModelAdmin construction (ImproperlyConfigured).
If the permission is missing, the toolbar may show a disabled control (unlike row actions). Import/export buttons are injected here as well when those options are present.
ObjectActionsOption
Names of ModelAdmin methods decorated with @object_action. They appear on
the change form toolbar and get a route:
{admin}/{app}/{model}/{object_id}/actions/{action_name}/
from django_chassis.options import ObjectActionsOption
ObjectActionsOption(actions=['publish', 'archive'])
| Field | Type | Default |
|---|---|---|
actions | list[str] | [] |
Duplicate names raise ValueError('Chassis object action names must be unique.').
An undecorated name fails validation at construction.
Decorator parameters are documented on Object actions.
RelatedEntitiesOption / RelatedEntityOption
Independent paginated tables below the fieldsets on the change form
(after_field_sets). Each section calls a @classmethod marked
@chassis_related_items.
from django_chassis.decorators import chassis_related_items
from django_chassis.options import RelatedEntitiesOption, RelatedEntityOption, TableColumnOption, TableOption
RelatedEntitiesOption(
sections=[
RelatedEntityOption(
slug='books',
title='Books',
get_items_method='get_books',
page_size=10,
table=TableOption(
columns=[TableColumnOption(field='title', label='Title'), TableColumnOption(field='isbn', label='ISBN')]
),
)
],
fieldset_title='Related',
collapsed=False,
pagination_state_ttl_seconds=30 * 60,
)
RelatedEntitiesOption
| Field | Type | Default | Required |
|---|---|---|---|
sections | list[RelatedEntityOption] | — | yes |
fieldset_title | localized string | 'Связанные сущности' | no |
collapsed | bool | False | no |
pagination_state_ttl_seconds | int | 1800 | no — must be >= 1 |
RelatedEntityOption
| Field | Type | Default | Required |
|---|---|---|---|
slug | unique section id | — | yes |
title | localized string | — | yes |
get_items_method | method name | — | yes |
table | TableOption | — | yes |
page_size | int | 10 | no — must be >= 1 |
collapsed | bool or None | None (inherit parent) | no |
Provider signature: (cls, request, obj) -> QuerySet | Sequence.
Pagination is per section; page state lives in the query string / session
for pagination_state_ttl_seconds.
TableOption family
Reusable table contract for related entities, information pages, and history-style blocks.
from django_chassis.options import TableActionOption, TableActionUrlKwargOption, TableColumnOption, TableOption
TableOption(
columns=[TableColumnOption(field='title', label='Title'), TableColumnOption(field='status', label='Status')],
fieldset_title='Items',
empty_message='No rows.',
selection_field='id',
selection_disabled_field='locked',
selection_checked_field='selected',
actions=[
TableActionOption(
url_name='admin:catalog_book_change',
label='Open',
icon_class='fa-solid fa-arrow-right',
object_field='id',
object_url_kwarg='object_id',
permission='view',
url_kwargs=[TableActionUrlKwargOption(name='extra', value='kind')],
)
],
)
TableOption
| Field | Type | Default |
|---|---|---|
columns | list[TableColumnOption] | required |
fieldset_title | localized string or None | None |
actions | list[TableActionOption] | [] |
selection_field | row attribute or None | None — checkbox value |
selection_disabled_field | row attribute or None | None — truthy disables |
selection_checked_field | row attribute or None | None — truthy pre-checks |
empty_message | localized string | 'Нет данных для отображения.' |
TableColumnOption
| Field | Type | Required |
|---|---|---|
field | dotted path on the row | yes |
label | column header | yes |
TableActionOption
| Field | Type | Default |
|---|---|---|
url_name | Django URL name | required |
label | localized string | required |
icon_class | Font Awesome class | required |
color | ButtonColor | PRIMARY |
display | RowActionDisplay | ICON |
object_field | row attribute for the object id | 'id' |
object_url_kwarg | URL kwarg name | 'object_id' |
permission | codename or None | None |
condition_method | method name or None | None |
url_kwargs | extra TableActionUrlKwargOption | [] |
TableActionUrlKwargOption(name, value) adds a constant keyword
argument to reverse(). The object id still comes from object_field
→ object_url_kwarg. If url_name has no :, Chassis prefixes the
current AdminSite name.
permission=None allows the action. A named condition_method that is
missing raises TypeError at render time.
ImportOption
Adds an Import toolbar button and the import routes (upload, preview, apply, history, download).
from django_chassis.enums import ImportFormat
from django_chassis.options import ImportOption
ImportOption(
permission='import_book', fields=['title', 'isbn', 'status'], formats=[ImportFormat.JSON, ImportFormat.XML]
)
| Field | Type | Default | Required |
|---|---|---|---|
permission | non-blank str | — | yes |
fields | list[str] or None | None — all eligible fields | no |
formats | list[ImportFormat] or None | None — every ImportFormat | no |
Validation at construction:
- blank
permission→ValueError formats=[]→ValueError- non-
ImportFormatmembers →TypeError
ImportFormat: JSON, XML.
The permission must exist on the model (or as a PermissionOption).
manage.py check reports chassis.E003 otherwise.
ExportOption
Adds an Export toolbar button and export routes (form, history, download).
from django_chassis.enums import ExportFormat
from django_chassis.options import ExportOption
ExportOption(
permission='export_book',
fields=['title', 'isbn', 'status'],
formats=[ExportFormat.JSON, ExportFormat.CSV, ExportFormat.XLSX],
filter_fields=['status', 'author'],
include_journals=False,
)
| Field | Type | Default | Required |
|---|---|---|---|
permission | non-blank str | — | yes |
fields | list[str] or None | None | no |
formats | list[ExportFormat] or None | None — all enum members | no |
include_journals | bool | False | no — include model history when the project provides it |
filter_fields | list[str] or None | None | no — Django lookups on the export form |
Validation:
- blank
permission→ValueError - empty
formats/filter_fieldslists →ValueError - unknown
filter_fieldslookups →chassis.E004at check time
ExportFormat: JSON, XML, CSV, XLSX.
Files go to STORAGES['media']. See Import and export.
Site-level options
These are not in ModelAdmin.options. They live on
ChassisAdminSiteMixin.
SidebarSectionOption
Collapsible sidebar group.
| Field | Type | Default |
|---|---|---|
slug | str | required |
label | localized string | required |
icon_class | Font Awesome class | required |
items | list[SidebarModelItemOption | SidebarPageItemOption] | required |
icon_color | SidebarIconColor | SLATE |
SidebarModelItemOption
| Field | Type | Default |
|---|---|---|
model | 'app_label.model' | required — must be registered on this site |
label | localized string or None | model verbose name |
icon_class | Font Awesome class | 'fa-solid fa-table-list' |
Hidden when the user lacks model permissions.
SidebarPageItemOption
| Field | Type | Default |
|---|---|---|
page_slug | str | required — page in chassis_page_classes |
label | localized string or None | page label |
icon_class | Font Awesome class | '' |
The page instance must be a PermissionAdminPage. Personal and
superuser pages cannot be sidebar children (ImproperlyConfigured).
SidebarLinkOption
Standalone top-level link (not inside a section).
| Field | Type | Default |
|---|---|---|
slug | str | required |
label | localized string | required |
icon_class | Font Awesome class | required |
url_name | Django URL name | required |
Duplicate slugs and unknown model/page references fail site checks.
AdminPageGroupOption
Groups custom pages into a navbar dropdown and/or a dashboard actions
section. Reused as AdminPage.navbar_group and AdminPage.dashboard_group.
| Field | Type | Default |
|---|---|---|
slug | str | required |
label | localized string | required |
icon_class | Font Awesome class | required |
order | int | 0 |
PersonalAdminPage cannot join a group.
PermissionOption
Declares a permission that Chassis registers and creates after migrate.
from django_chassis.options import PermissionOption
PermissionOption(app_label='catalog', model='book', codename='export_book', name='Can export book')
| Field | Type | Constraint |
|---|---|---|
app_label | str | Python identifier |
model | str | lowercase identifier |
codename | str | identifier |
name | localized string | non-empty |
value property: '{app_label}.{codename}'.
Assign on the site as chassis_permission_options = (export_books,).
PermissionAdminPage.permission must be a view_* PermissionOption.
Construction and checks
| Failure | When | What |
|---|---|---|
ValueError / TypeError | option __post_init__ | blank import/export permission, empty lists, duplicate action names, non-positive page size |
ImproperlyConfigured | ModelAdmin / site __init__ | missing condition classmethods, bad decimal fields, invalid page access contracts |
chassis.E002 | manage.py check | Django @admin.action without allowed_permissions |
chassis.E003 | manage.py check | action / import / export permission not declared on the model |
chassis.E004 | manage.py check | unknown ExportOption.filter_fields lookup |
See also
- ModelAdmin — MRO,
optionslist, companion mixins - Changelist — how the list page is assembled
- API reference — compact signatures