While the default admin is useful, customizing it makes it much more powerful for your specific needs.
Using ModelAdmin
Create a ModelAdmin class to customize how a model appears:
python# polls/admin.py from django.contrib import admin from .models import Question, Choice class QuestionAdmin(admin.ModelAdmin): # Fields to display in list view list_display = ['question_text', 'pub_date', 'was_published_recently'] # Add filters to the sidebar list_filter = ['pub_date'] # Add a search box search_fields = ['question_text'] # Default ordering ordering = ['-pub_date'] # Add date hierarchy navigation date_hierarchy = 'pub_date' admin.site.register(Question, QuestionAdmin) admin.site.register(Choice)
Customizing the Change Form
Control how the edit form looks:
pythonclass QuestionAdmin(admin.ModelAdmin): # Group fields into fieldsets fieldsets = [ (None, {'fields': ['question_text']}), ('Date Information', { 'fields': ['pub_date'], 'classes': ['collapse'], # Collapsible section }), ] # Or simple field ordering # fields = ['pub_date', 'question_text'] # Read-only fields readonly_fields = ['pub_date']
Inline Editing
Edit related objects on the same page:
pythonclass ChoiceInline(admin.TabularInline): # Or admin.StackedInline model = Choice extra = 3 # Show 3 empty forms class QuestionAdmin(admin.ModelAdmin): list_display = ['question_text', 'pub_date'] inlines = [ChoiceInline] # Edit choices on question page admin.site.register(Question, QuestionAdmin) # Don't need to register Choice separately anymore
List View Customization
The list view supports several options for controlling how data is displayed, which fields are editable inline, and how many items appear per page.
pythonclass QuestionAdmin(admin.ModelAdmin): # Columns to display list_display = ['question_text', 'pub_date', 'choice_count'] # Make fields editable in list view list_editable = ['pub_date'] # Clickable fields (link to change page) list_display_links = ['question_text'] # Items per page list_per_page = 25 # Custom method for display @admin.display(description='Number of Choices') def choice_count(self, obj): return obj.choice_set.count()
Using the Decorator Syntax
A cleaner way to register:
pythonfrom django.contrib import admin from .models import Question @admin.register(Question) class QuestionAdmin(admin.ModelAdmin): list_display = ['question_text', 'pub_date'] search_fields = ['question_text']
Admin Site Customization
Customize the admin site itself:
python# mysite/admin.py or polls/admin.py admin.site.site_header = 'My Site Administration' admin.site.site_title = 'My Site Admin' admin.site.index_title = 'Welcome to the Admin Panel'
Common Pitfalls
- Putting a non-existent field in
list_display: Django raises aFieldDoesNotExisterror. Double-check field names match your model. - Using
list_editablewithoutlist_display: Fields inlist_editablemust also appear inlist_display, and the first field inlist_displaycannot be editable. - Forgetting
extra = 0on inlines: By default, Django shows 3 empty inline forms. Setextra = 0to show only existing related objects.
Best Practices
- Use
@admin.register(Model)decorator instead ofadmin.site.register()for cleaner code. - Add
search_fieldsandlist_filterto every ModelAdmin for easy data discovery. - Use fieldsets to organize the change form into logical groups with collapsible sections.
Summary
- Customize the admin by creating
ModelAdminclasses with options likelist_display,list_filter, andsearch_fields - Use
fieldsetsto organize edit forms into collapsible sections - Inline editing (
TabularInline,StackedInline) lets you edit related objects on the same page - Add computed columns with
@admin.displaydecorated methods - Customize the admin site header and title with
admin.site.site_header
Code Examples
python
@admin.register(Question)
class QuestionAdmin(admin.ModelAdmin):
list_display = ['question_text', 'pub_date', 'choice_count']
list_filter = ['pub_date']
search_fields = ['question_text']
ordering = ['-pub_date']
@admin.display(description='Number of Choices')
def choice_count(self, obj):
return obj.choice_set.count()