Customizing ModelAdmin
The ModelAdmin class is the central point for customizing the Django admin interface for a specific model. In this codebase, it inherits from BaseModelAdmin, which provides shared functionality for both standard admin pages and inline admin interfaces.
Core Architecture
The implementation is split between two primary classes in django/contrib/admin/options.py:
BaseModelAdmin: Handles form-centric logic, including field definitions (fields,exclude), fieldsets, form overrides, and permissions.ModelAdmin: ExtendsBaseModelAdminto provide the full admin interface, including the "Change List" (list view), search functionality, filters, and the standard views for adding, changing, and deleting objects.
Customizing the Change List
The Change List view is the primary entry point for managing model instances. It is customized using several key attributes.
Column Display and Links
The list_display attribute controls which fields appear as columns in the list view. By default, it only shows the string representation of the object.
class EmployeeAdmin(ModelAdmin):
# Displays 'name' and 'department' columns
list_display = ["name", "department"]
The first field in list_display automatically becomes a link to the change view. You can customize this using list_display_links.
Filtering and Searching
Filters appear in the right sidebar, while the search box appears at the top.
list_filter: Supports field names, relationship lookups, and custom filter classes.search_fields: Defines which fields are searched. You can use prefixes to control the lookup type:^:istartswith=:iexact@:search(Full-text search)- No prefix:
icontains
class BookAdmin(ModelAdmin):
list_filter = (
"year",
"author",
("is_best_seller", BooleanFieldListFilter), # Custom filter class
)
search_fields = ["^title", "author__name"] # Starts with title, contains author name
Bulk Editing
The list_editable attribute allows users to edit fields directly on the change list page. Fields in list_editable must also be present in list_display.
Form and Layout Customization
BaseModelAdmin provides the logic for how the add/change forms are structured.
Fields and Fieldsets
You can control the order and grouping of fields using fields or fieldsets.
class BandAdmin(ModelAdmin):
# Grouping fields into sections
fieldsets = [
(None, {"fields": ["name"]}),
("Advanced options", {
"classes": ["collapse"],
"fields": ["bio", "genre"],
}),
]
Inlines
To edit related models on the same page, use inlines. The ModelAdmin.get_inline_instances method handles the instantiation of these related admin classes.
class BookAdmin(ModelAdmin):
inlines = [AuthorInline]
Dynamic Customization via Methods
Many attributes have corresponding get_* methods that allow for dynamic behavior based on the request or the object being edited.
Customizing the Queryset
Override get_queryset to restrict which objects a user can see or edit.
class BookAdminWithCustomQueryset(ModelAdmin):
def get_queryset(self, request):
qs = super().get_queryset(request)
# Only show books authored by the current user
return qs.filter(author=request.user)
Dynamic Forms
The get_form method is used to generate the ModelForm class for the add and change views. It uses modelform_factory internally to merge ModelAdmin options with the model's fields.
def get_form(self, request, obj=None, change=False, **kwargs):
# Custom logic to modify form defaults before factory creation
return super().get_form(request, obj, change, **kwargs)
Model Persistence Hooks
ModelAdmin provides hooks to intercept the saving and deleting of objects, allowing for custom logic (like sending notifications or updating related data).
save_model(request, obj, form, change): Called when saving the main object.delete_model(request, obj): Called when deleting a single object.save_related(request, form, formsets, change): Called after the main object is saved to handle Many-to-Many relationships and inlines.
Admin Actions
Actions allow for bulk operations on selected items in the change list.
Defining Actions
Actions are defined as methods on the ModelAdmin class and added to the actions attribute.
class MyAdmin(ModelAdmin):
actions = ["make_published"]
@admin.action(description="Mark selected stories as published")
def make_published(self, request, queryset):
queryset.update(status="p")
Action Locations
The codebase uses ActionLocation (an Enum) to determine where actions are displayed. By default, they appear on the CHANGE_LIST, but they can also be configured for the CHANGE_FORM.
Warning: Overriding
get_actions()orget_action_choices()without theaction_locationparameter is deprecated in this version of the codebase.
Media and Assets
The media property (inherited from forms.MediaDefiningClass) allows you to inject custom JavaScript and CSS into the admin pages. ModelAdmin includes several default scripts like RelatedObjectLookups.js and actions.js to handle standard admin interactions.
@property
def media(self):
# Returns a forms.Media object with admin-specific JS
return super().media + forms.Media(js=["custom_admin.js"])