Skip to main content

ModelAdmin

Added in 1.0.1

ChassisAdminMixin is the ModelAdmin entry point. Put it first in the MRO. Attach capabilities through options.

from django.contrib.admin import ModelAdmin

from django_chassis.mixins import ChassisAdminMixin
from django_chassis.options import RowActionsOption, SearchOption, Settings


class BookAdmin(ChassisAdminMixin, ModelAdmin):
chassis_settings = Settings(search_collapsed=True, allow_standard_add=True)
options = [SearchOption(fields=['title']), RowActionsOption()]

MRO

class BookAdmin(ChassisAdminMixin, ModelAdmin): # correct
...


class BookAdmin(ModelAdmin, ChassisAdminMixin): # wrong — hooks will not wrap super()
...

The same rule applies to ReadOnlyAdminMixin and NoDeleteAdminMixin: they must sit where their has_*_permission overrides still run.

Change-form anatomy

Template: admin/chassis/change_form.html (extends admin/change_form.html).

┌─ breadcrumbs ─────────────────────────────────────────────┐
│ Dashboard › Section › Model › object │
├─ toolbar (`page_actions`) ────────────────────────────────┤
│ [@object_action buttons…] [Django history / …] │
├─ Django fieldsets / inlines ──────────────────────────────┤
│ Pretty JSON / decimal widgets / date masks │
├─ related entities (`after_field_sets`) ───────────────────┤
│ One fieldset per RelatedEntityOption (paginated table) │
├─ submit row ──────────────────────────────────────────────┤
│ [Save] [Back] [Delete] │
└───────────────────────────────────────────────────────────┘

Object actions require ObjectActionsOption plus @object_action on the methods. Related tables require RelatedEntitiesOption. See Object actions and Related entities.

The first column of the changelist is not a link by default. Users reach this page through a row action (RowActionType.VIEW or CHANGE).

How get_chassis_option resolves

  1. Walk self.options and return the first instance of the requested type.
  2. If none, walk ChassisAdminMixin.options (today: a default RowActionsOption()).
  3. Composite things (several FK groups, several row actions) live inside one option object.

There is no merging of two SearchOption instances. The local one wins.

options

options is a list of frozen dataclasses. Do not rename this attribute.

Full field tables, validation, and UI regions: Options catalog.

AdminOption is the union of:

  • SearchOption
  • FiltersOption
  • DateHierarchyOption
  • FieldTabsOption
  • ForeignKeyTabsOption
  • BadgeFieldsOption
  • DecimalAmountOption
  • PrettyJsonOption
  • RowActionsOption
  • ListActionsOption
  • ObjectActionsOption
  • RelatedEntitiesOption
  • ImportOption
  • ExportOption

The mixin default is [RowActionsOption()]. If you set options yourself, include RowActionsOption when you still want the last-column buttons.

Settings

Not an option. Assigned to chassis_settings.

ParameterDefaultPurpose
search_collapsedTrueStart with the search fieldset collapsed
date_hierarchy_collapsedTrueCollapse the date hierarchy fieldset
filters_collapsedTrueCollapse the filters fieldset
allow_standard_addTrueWhen False, has_add_permission() is False

Other mixin attributes

AttributeDefaultPurpose
change_list_templateadmin/chassis/change_list.htmlChassis changelist
change_form_templateadmin/chassis/change_form.htmlChassis change form
chassis_link_first_columnFalseFirst column is not a change-link

Row actions are the intended entry point into an object. Set chassis_link_first_column = True only if you want Django's classic first column link.

Companion mixins

  • ReadOnlyAdminMixin — deny add, change, and delete
  • NoDeleteAdminMixin — deny delete

Put the denial mixin before ChassisAdminMixin when its has_*_permission overrides must win:

class LogAdmin(ReadOnlyAdminMixin, ChassisAdminMixin, ModelAdmin):
options = [SearchOption(fields=['message'])]

System checks

ChassisAdminMixin runs checks for action permissions and export lookups. Failures show up as Django system checks, not silent template gaps.

See also