1.ModelAdmin basics
ModelAdmin configures how ONE model appears and behaves in the admin. list_display picks the columns shown on the list page (fields, related-field lookups like "author__name", or a method taking the instance). list_filter adds a sidebar of filters; search_fields (icontains by default, with ^/=/@ prefixes for other lookup types) adds a search box. ordering sets the default sort; readonly_fields displays a field without letting it be edited; fieldsets groups the edit form's fields into labeled sections instead of one flat list.
Key features
- list_display accepts a plain field name, a related field via __ (e.g. "author__name" — though this shows the value, not an editable link, unless separately configured), or a callable/method taking the model instance as its argument
- ManyToManyField is NOT supported in list_display directly — showing it would require a separate query per row for every M2M value, which Django refuses to do implicitly
- search_fields defaults to icontains — prefix a field with ^ for istartswith, = for iexact, or @ for PostgreSQL full-text search
- readonly_fields displays a field's value without an editable input — works for both real model fields and callables/methods, useful for showing a computed or system-managed value
- fieldsets is a list of (name, {"fields": [...], "classes": [...]}) tuples — a tuple of field names inside "fields" displays those fields on the SAME line instead of stacked
The core ModelAdmin list/search/form options
- Whole: class ArticleAdmin(admin.ModelAdmin): list_display = ["title", "author", "status"] list_filter = ["status"] search_fields = ["title", "author__email"] ordering = ["-published_at"] readonly_fields = ["created_at"]
- list_display — list_display: which columns appear on the changelist page
- list_filter — list_filter: the sidebar filter widgets
- search_fields — search_fields: which fields the search box queries, and how
- ordering — ordering: the default sort order for the changelist
- readonly_fields — readonly_fields: shown on the change form but not editable
Command
@admin.register(Model)
class ModelAdminClass(admin.ModelAdmin):
list_display = [...]
fieldsets = [(None, {"fields": [...]}), ("Advanced", {"classes": ["collapse"], "fields": [...]})]list_display accepts fields, related-field lookups (__), or callables — never a ManyToManyField directly (a real N+1 risk Django refuses to do implicitly). search_fields defaults to icontains; ^/=/@ prefixes switch to istartswith/iexact/full-text. fieldsets groups the edit form into labeled, optionally-collapsed sections.