Overview
This guide will walk you through creating your first Django admin interface with Unfold. You’ll learn how to set up a basic model admin, customize the display, and leverage Unfold’s powerful features.
Your First Unfold Admin
Step 1: Create a Model
First, let’s create a simple Django model. For this example, we’ll build a blog post model:
from django.db import models
from django.utils.translation import gettext_lazy as _
class Post ( models . Model ):
class StatusChoices ( models . TextChoices ):
DRAFT = "draft" , _( "Draft" )
PUBLISHED = "published" , _( "Published" )
ARCHIVED = "archived" , _( "Archived" )
title = models.CharField(_( "Title" ), max_length = 200 )
slug = models.SlugField(_( "Slug" ), max_length = 200 , unique = True )
content = models.TextField(_( "Content" ))
status = models.CharField(
_( "Status" ),
max_length = 20 ,
choices = StatusChoices.choices,
default = StatusChoices. DRAFT ,
)
author = models.ForeignKey(
"auth.User" ,
on_delete = models. CASCADE ,
related_name = "posts" ,
)
created_at = models.DateTimeField(_( "Created at" ), auto_now_add = True )
updated_at = models.DateTimeField(_( "Updated at" ), auto_now = True )
class Meta :
verbose_name = _( "Post" )
verbose_name_plural = _( "Posts" )
ordering = [ "-created_at" ]
def __str__ ( self ):
return self .title
Step 2: Register with Unfold
Now, create an admin class using Unfold’s ModelAdmin:
from django.contrib import admin
from unfold.admin import ModelAdmin
from .models import Post
@admin.register (Post)
class PostAdmin ( ModelAdmin ):
list_display = [ "title" , "author" , "status" , "created_at" ]
list_filter = [ "status" , "created_at" , "author" ]
search_fields = [ "title" , "content" ]
prepopulated_fields = { "slug" : [ "title" ]}
fieldsets = (
( None , {
"fields" : ( "title" , "slug" , "content" ),
}),
( "Metadata" , {
"fields" : ( "status" , "author" ),
}),
)
Import ModelAdmin
Import ModelAdmin from unfold.admin instead of django.contrib.admin
Register Your Model
Use the @admin.register() decorator or admin.site.register() as usual
Configure Display
Use standard Django admin options like list_display, list_filter, etc.
Step 3: Run Migrations
Create and apply database migrations for your model:
python manage.py makemigrations
python manage.py migrate
Step 4: Access the Admin
Start your development server and access the admin:
python manage.py runserver
Navigate to http://127.0.0.1:8000/admin/ and log in. You’ll see your Post model with Unfold’s modern interface!
Congratulations! You’ve created your first Unfold admin interface.
Enhancing Your Admin
Custom Display Methods
Add custom display methods with Unfold’s @display decorator:
from django.contrib import admin
from unfold.admin import ModelAdmin
from unfold.decorators import display
from .models import Post
@admin.register (Post)
class PostAdmin ( ModelAdmin ):
list_display = [ "title" , "display_status" , "author" , "created_at" ]
list_filter = [ "status" , "created_at" ]
search_fields = [ "title" , "content" ]
@display ( description = "Status" , label = True )
def display_status ( self , obj ):
return obj.status
@display ( description = "Published Date" , ordering = "created_at" )
def display_created ( self , obj ):
return obj.created_at.strftime( "%B %d , %Y" )
The @display decorator from unfold.decorators provides enhanced functionality including labels, badges, and custom HTML rendering.
Adding Inlines
Let’s add inline editing for related models. First, create a Comment model:
class Comment ( models . Model ):
post = models.ForeignKey(
Post,
on_delete = models. CASCADE ,
related_name = "comments" ,
)
author = models.ForeignKey( "auth.User" , on_delete = models. CASCADE )
content = models.TextField(_( "Content" ))
created_at = models.DateTimeField(_( "Created at" ), auto_now_add = True )
class Meta :
verbose_name = _( "Comment" )
verbose_name_plural = _( "Comments" )
ordering = [ "-created_at" ]
def __str__ ( self ):
return f "Comment by { self .author } on { self .post } "
Then add an inline to your admin:
from unfold.admin import ModelAdmin, StackedInline, TabularInline
class CommentInline ( TabularInline ):
model = Comment
extra = 1
fields = [ "author" , "content" , "created_at" ]
readonly_fields = [ "created_at" ]
@admin.register (Post)
class PostAdmin ( ModelAdmin ):
list_display = [ "title" , "author" , "status" , "created_at" ]
list_filter = [ "status" , "created_at" ]
search_fields = [ "title" , "content" ]
inlines = [CommentInline]
TabularInline
StackedInline
from unfold.admin import TabularInline
class CommentInline ( TabularInline ):
model = Comment
extra = 1
Advanced Features
Compressed Fields
For forms with many fields, enable compressed mode:
@admin.register (Post)
class PostAdmin ( ModelAdmin ):
compressed_fields = True # Enable compressed field display
list_display = [ "title" , "status" , "created_at" ]
Custom Actions
Add custom actions with Unfold’s @action decorator:
from django.contrib import messages
from unfold.decorators import action
@admin.register (Post)
class PostAdmin ( ModelAdmin ):
list_display = [ "title" , "status" , "created_at" ]
actions = [ "make_published" , "make_draft" ]
@action ( description = "Mark selected posts as published" )
def make_published ( self , request , queryset ):
updated = queryset.update( status = Post.StatusChoices. PUBLISHED )
self .message_user(
request,
f " { updated } post(s) marked as published." ,
messages. SUCCESS ,
)
@action ( description = "Mark selected posts as draft" )
def make_draft ( self , request , queryset ):
updated = queryset.update( status = Post.StatusChoices. DRAFT )
self .message_user(
request,
f " { updated } post(s) marked as draft." ,
messages. SUCCESS ,
)
Advanced Filters
Use Unfold’s enhanced filters for better user experience:
from unfold.admin import ModelAdmin
from unfold.contrib.filters.admin import (
ChoicesDropdownFilter,
RangeDateFilter,
RelatedDropdownFilter,
)
@admin.register (Post)
class PostAdmin ( ModelAdmin ):
list_display = [ "title" , "author" , "status" , "created_at" ]
list_filter = [
( "status" , ChoicesDropdownFilter),
( "created_at" , RangeDateFilter),
( "author" , RelatedDropdownFilter),
]
search_fields = [ "title" , "content" ]
To use advanced filters, ensure you’ve added unfold.contrib.filters to your INSTALLED_APPS in settings.py.
Real-World Example
Here’s a complete example from Unfold’s test suite showing advanced features:
from django.contrib import admin
from django.utils.html import format_html
from unfold.admin import ModelAdmin, StackedInline
from unfold.contrib.filters.admin import (
ChoicesDropdownFilter,
RangeDateFilter,
)
from unfold.decorators import action, display
class CommentInline ( StackedInline ):
model = Comment
extra = 0
fields = [ "author" , "content" , "created_at" ]
readonly_fields = [ "created_at" ]
collapsible = True # Make inline collapsible
@admin.register (Post)
class PostAdmin ( ModelAdmin ):
# Display configuration
list_display = [
"title" ,
"display_status" ,
"author" ,
"display_comments_count" ,
"created_at" ,
]
list_filter = [
( "status" , ChoicesDropdownFilter),
( "created_at" , RangeDateFilter),
"author" ,
]
search_fields = [ "title" , "content" ]
prepopulated_fields = { "slug" : [ "title" ]}
# Form configuration
fieldsets = (
( None , {
"fields" : ( "title" , "slug" , "content" ),
}),
( "Publication" , {
"fields" : ( "status" , "author" ),
"classes" : [ "tab" ], # Display as tab
}),
)
# Inlines
inlines = [CommentInline]
# Custom display methods
@display ( description = "Status" , label = True )
def display_status ( self , obj ):
return obj.status
@display ( description = "Comments" )
def display_comments_count ( self , obj ):
count = obj.comments.count()
return format_html(
'<span style="font-weight: bold;"> {} </span>' ,
count
)
# Custom actions
@action ( description = "Publish selected posts" )
def make_published ( self , request , queryset ):
queryset.update( status = Post.StatusChoices. PUBLISHED )
self .message_user(request, "Posts published successfully." )
Available Options
Unfold’s ModelAdmin supports all standard Django admin options plus additional features:
list_display - Fields to show in list view
list_filter - Filters in sidebar
search_fields - Searchable fields
list_horizontal_scrollbar_top - Add scrollbar at top
list_fullwidth - Full-width list view
list_disable_select_all - Disable select all checkbox
inlines - Related models to edit inline
per_page - Pagination for inlines
collapsible - Make inlines collapsible
ordering_field - Field for drag-and-drop ordering
hide_ordering_field - Hide ordering field column
actions - Custom bulk actions
action_form - Custom action form
Custom detail/row/list actions via decorators
Next Steps
Explore Features Dive deep into all available features and customization options
Live Demo See all features in action with the interactive demo
Example Project Clone a complete example implementation
Join Community Get help and share your experience on Discord
You’re now ready to build powerful admin interfaces with Django Unfold!