Django Admin Fields
Django's admin interface provides a powerful way to manage your application's data. One of its greatest strengths is how easily you can customize the fields displayed in the admin interface without having to build a custom interface from scratch.
Introduction
When working with Django models, you'll often want to control how these models are presented in the admin interface. Django's admin provides several ways to customize the fields that are displayed, how they're displayed, and what actions can be performed on them.
In this tutorial, you'll learn:
- How to specify which fields appear in the admin
- How to customize field display and behavior
- How to add custom fields that aren't directly part of your model
- Advanced field customizations for better user experience
Basic Field Configuration
Controlling Field Display
The simplest way to control which fields appear in the Django admin is by using the fields
and list_display
attributes in your ModelAdmin
class.
from django.contrib import admin
from .models import Book
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
# Fields to display in the list view
list_display = ('title', 'author', 'publication_date', 'is_bestseller')
# Fields to display in the detail form
fields = ('title', 'author', 'description', 'cover_image', 'publication_date', 'is_bestseller')
In this example:
list_display
controls which fields appear in the table view of booksfields
controls which fields appear in the detail/edit form
Grouping Fields with Fieldsets
For forms with many fields, you can organize them using fieldsets:
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
fieldsets = (
('Basic Information', {
'fields': ('title', 'author', 'publication_date')
}),
('Additional Details', {
'fields': ('description', 'cover_image'),
'classes': ('collapse',), # Makes this section collapsible
}),
('Status', {
'fields': ('is_bestseller', 'in_stock')
}),
)
The fieldsets
attribute takes a tuple of 2-tuples, where each 2-tuple represents a section. The first element is the section title, and the second is a dictionary containing the fields and optional CSS classes.
Customizing Field Display
Read-only Fields
Sometimes you want to display fields that shouldn't be edited:
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
readonly_fields = ('created_at', 'updated_at', 'sales_count')
Custom Field Display Methods
You can create custom methods to display derived or formatted data:
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'publication_year', 'price_with_currency')
def publication_year(self, obj):
return obj.publication_date.year if obj.publication_date else "N/A"
publication_year.short_description = "Year" # Custom column header
def price_with_currency(self, obj):
return f"${obj.price:.2f}" if obj.price else "Not priced"
price_with_currency.short_description = "Price"
In this example, publication_year
extracts just the year from a date field, and price_with_currency
formats the price with a dollar sign.
Adding Non-model Fields
Including Related Fields
You can include fields from related models:
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'author_name', 'publisher_name')
def author_name(self, obj):
return obj.author.full_name if obj.author else "Unknown"
author_name.short_description = "Author"
def publisher_name(self, obj):
return obj.publisher.name if obj.publisher else "Self-published"
publisher_name.short_description = "Publisher"
Computed Properties
You can add computed properties that don't exist in the database:
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'is_recent_publication')
def is_recent_publication(self, obj):
import datetime
if not obj.publication_date:
return False
return obj.publication_date >= datetime.date.today() - datetime.timedelta(days=90)
is_recent_publication.boolean = True # Display as a checkmark/cross icon
is_recent_publication.short_description = "Recent Publication"
The .boolean = True
attribute tells Django to display this field as a checkmark or X icon.
Advanced Field Customization
List Display Links
By default, only the first column in list_display
is linked to the detail/edit page. You can customize this:
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'publication_date')
list_display_links = ('title', 'author') # Both title and author are now clickable
Editable Fields
You can make fields directly editable in the list view:
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'is_bestseller', 'in_stock')
list_editable = ('is_bestseller', 'in_stock') # These fields can be edited directly in the list
Note: Fields in list_editable
cannot also be in list_display_links
.
Custom Ordering
You can specify the default ordering and allow users to sort by custom fields:
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'publication_year', 'page_count')
ordering = ('-publication_date',) # Default ordering
sortable_by = ('title', 'author', 'publication_year') # Fields that can be sorted by clicking column headers
def publication_year(self, obj):
return obj.publication_date.year if obj.publication_date else "N/A"
Practical Real-world Examples
E-commerce Product Admin
Here's a more comprehensive example for an e-commerce product model:
from django.contrib import admin
from django.utils.html import format_html
from .models import Product
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'thumbnail_preview', 'category', 'price_display', 'stock_status', 'is_active')
list_filter = ('category', 'is_active', 'created_at')
search_fields = ('name', 'description', 'sku')
readonly_fields = ('created_at', 'updated_at', 'image_preview')
list_editable = ('is_active',)
fieldsets = (
('Basic Information', {
'fields': ('name', 'sku', 'description', 'category')
}),
('Pricing', {
'fields': ('price', 'discount_price', 'on_sale')
}),
('Inventory', {
'fields': ('stock_quantity', 'is_active')
}),
('Media', {
'fields': ('image', 'image_preview')
}),
('Metadata', {
'fields': ('created_at', 'updated_at'),
'classes': ('collapse',),
}),
)
def price_display(self, obj):
if obj.on_sale and obj.discount_price:
return format_html(
'<span style="text-decoration: line-through">${:.2f}</span> '
'<span style="color: red">${:.2f}</span>',
obj.price, obj.discount_price
)
return f"${obj.price:.2f}"
price_display.short_description = "Price"
def stock_status(self, obj):
if obj.stock_quantity <= 0:
return format_html('<span style="color: red">Out of Stock</span>')
elif obj.stock_quantity < 10:
return format_html('<span style="color: orange">Low Stock ({0})</span>', obj.stock_quantity)
return format_html('<span style="color: green">In Stock ({0})</span>', obj.stock_quantity)
stock_status.short_description = "Stock Status"
def thumbnail_preview(self, obj):
if obj.image:
return format_html('<img src="{}" width="50" height="50" style="object-fit: cover;" />', obj.image.url)
return "No Image"
thumbnail_preview.short_description = "Thumbnail"
def image_preview(self, obj):
if obj.image:
return format_html('<img src="{}" width="300" />', obj.image.url)
return "No Image"
image_preview.short_description = "Image Preview"
This example demonstrates:
- Using
format_html
to safely render HTML in the admin - Creating visual representations of data (colored stock status, thumbnail previews)
- Organizing fields into logical sections
- Making certain fields read-only for safety
- Adding different views of the same data (thumbnail in list, larger preview in detail)
Form Field Overrides
You can customize specific form fields using the formfield_overrides
attribute:
from django.db import models
from django.contrib import admin
from django import forms
from .models import Book
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
formfield_overrides = {
models.TextField: {'widget': forms.Textarea(attrs={'rows': 20, 'cols': 100})},
models.CharField: {'widget': forms.TextInput(attrs={'size': 50})},
}
This code customizes all TextField
and CharField
widgets in your form.
Summary
Django Admin's field customization options provide a powerful way to create a tailored administrative interface without writing custom views or templates. We've covered:
- Controlling which fields are displayed with
fields
andlist_display
- Organizing fields with
fieldsets
- Creating custom display methods for fields
- Making fields read-only or directly editable
- Adding computed properties and fields from related models
- Advanced customization with HTML formatting and widgets
- Real-world examples showing these concepts in action
By mastering these techniques, you can create admin interfaces that are more intuitive, efficient, and helpful for content managers and administrators.
Additional Resources
Exercises
-
Create a
Blog
model with fields liketitle
,content
,author
,published_date
, andstatus
. Then create a custom admin that:- Shows a preview of the first 50 characters of content in the list view
- Groups fields into "Content", "Publishing", and "Meta" fieldsets
- Makes the publication date read-only if the status is "published"
-
For an existing model in your project, add a custom field that displays how long ago an item was created (e.g., "2 days ago", "5 hours ago").
-
Create a custom admin for a
Product
model that displays an image thumbnail in the list view and a larger preview in the detail view. -
Implement custom filters and search fields to make your admin more user-friendly for a model with many records.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)