Customizing the Admin
The previous lesson registered TaskFlow's models with a single line each — admin.site.register(Task)
— and got a fully working admin in return. But "working" and "pleasant to use every day" aren't the
same thing. This lesson is about closing that gap: subclassing admin.ModelAdmin to
control exactly which columns show up, adding filters and a search box, and even making some fields
editable directly from the list, without opening a single edit form.
Subclassing ModelAdmin
Every customization in this lesson starts the same way: instead of registering the bare model,
you define a class that inherits from admin.ModelAdmin and set attributes on it. Django
reads those attributes and changes how the admin behaves for that model accordingly:
# taskflow/admin.py
from django.contrib import admin
from .models import Task
@admin.register(Task)
class TaskAdmin(admin.ModelAdmin):
pass # attributes go here
list_display: Choosing List View Columns
By default, the admin's list view shows just one column — usually the model's string representation.
list_display lets you choose exactly which fields appear as columns instead:
Example: Showing Task Details as Columns
class TaskAdmin(admin.ModelAdmin):
list_display = ('title', 'project', 'priority', 'completed')
The task list now shows four real columns at a glance — title, which project it belongs to, its priority, and whether it's completed — instead of forcing you to open each task individually just to see that information.
list_filter: A Sidebar Filter
list_filter adds a filter sidebar to the right of the list view, letting you narrow the
visible rows by a field's value without writing any search query at all:
Example: Filtering by Priority and Completion
class TaskAdmin(admin.ModelAdmin):
list_display = ('title', 'project', 'priority', 'completed')
list_filter = ('priority', 'completed')
With this in place, the admin sidebar offers one-click links for each priority level and for completed versus incomplete tasks, letting you drill down to, say, "every high-priority task that isn't done yet" in two clicks.
search_fields: Adding a Search Box
search_fields puts a search box above the list view, matching against whichever fields
you list. Searching TaskFlow's tasks by title is a natural fit:
class TaskAdmin(admin.ModelAdmin):
search_fields = ('title',)
Typing into that box performs a case-insensitive partial match against title, similar
in spirit to an icontains lookup — you don't need to type a task's exact, full title to
find it.
list_editable: Editing Directly From the List
Opening a full edit form just to flip one checkbox is slow once you're managing dozens of tasks.
list_editable turns specific columns into editable inputs right inside the list view
itself — change several rows, then save them all in one submission:
Example: Toggling completed Inline
class TaskAdmin(admin.ModelAdmin):
list_display = ('title', 'project', 'priority', 'completed')
list_editable = ('completed',)
list_editable must also appear in list_display — the admin needs to be showing a column before it can make that column editable.ordering: The Default Sort Order
ordering controls the order rows appear in when the list view first loads, before any
column header is clicked to re-sort. Showing the newest or most urgent tasks first is usually more
useful than whatever order the database happens to return rows in:
class TaskAdmin(admin.ModelAdmin):
ordering = ('-due_date',)
The leading - reverses the sort, exactly the same convention used with
.order_by() on a QuerySet — tasks with the furthest-out due date appear first here.
readonly_fields: Showing a Field Without Allowing Edits
Some fields are useful to see on the edit form but shouldn't ever be changed by hand — a
created_at timestamp is the classic example. readonly_fields keeps a field
visible on the detail form while making it impossible to edit:
class TaskAdmin(admin.ModelAdmin):
readonly_fields = ('created_at',)
Putting It All Together
None of these options are mutually exclusive — a single ModelAdmin subclass typically
combines several of them at once. Here's a more complete TaskAdmin for TaskFlow, folding
in everything from this lesson:
Example: A Polished TaskAdmin
# taskflow/admin.py
from django.contrib import admin
from .models import Task
@admin.register(Task)
class TaskAdmin(admin.ModelAdmin):
list_display = ('title', 'project', 'priority', 'completed')
list_filter = ('priority', 'completed')
search_fields = ('title',)
list_editable = ('completed',)
ordering = ('-due_date',)
readonly_fields = ('created_at',)
That one class turns the bare, single-column admin list from the previous lesson into something genuinely usable day-to-day — sortable, filterable, searchable, and editable in place, all from declarative attributes rather than any custom view code.