Skip to Content
GuidesSample ProjectAdmin Interface

Admin Interface

The Django-CFG sample project showcases a modern, customizable admin interface built on the Unfold theme. This guide covers admin customization, dashboard widgets, and navigation configuration.

Unfold Theme Integration

The sample project uses the Unfold theme for a modern, Material Design-inspired admin interface.

Theme Configuration

Configure the theme in api/config.py:

from django_cfg import ( UnfoldConfig, UnfoldColors, UnfoldSidebar, NavigationSection, NavigationItem, Icons, ) unfold: UnfoldConfig = UnfoldConfig( site_title="Django-CFG Sample Admin", site_header="Django-CFG Sample", site_url="/", site_symbol=Icons.ROCKET_LAUNCH, colors=UnfoldColors(primary="#4F46E5"), sidebar=UnfoldSidebar( show_search=True, show_all_applications=True, ), navigation=[...], # NavigationSection list )

Theme Options

Basic Settings

UnfoldConfig( site_title="My Admin", # Browser tab title site_header="My Site Admin", # Admin header text site_url="/", # Logo link URL site_symbol=Icons.DASHBOARD, # Material icon name )

Colors

Customize the color scheme using UnfoldColors:

from django_cfg import UnfoldColors UnfoldConfig( colors=UnfoldColors(primary="#4F46E5"), )

Custom Navigation

Define a custom navigation menu using typed NavigationSection and NavigationItem objects:

from django_cfg import ( UnfoldConfig, NavigationSection, NavigationItem, Icons, ) unfold: UnfoldConfig = UnfoldConfig( navigation=[ NavigationSection( title="Content Management", separator=True, items=[ NavigationItem(title="Blog Posts", icon=Icons.ARTICLE, link="admin:blog_post_changelist"), NavigationItem(title="Comments", icon=Icons.COMMENT, link="admin:blog_comment_changelist"), ], ), NavigationSection( title="E-Commerce", separator=True, items=[ NavigationItem(title="Products", icon=Icons.INVENTORY, link="admin:shop_product_changelist"), NavigationItem(title="Orders", icon=Icons.SHOPPING_CART, link="admin:shop_order_changelist"), ], ), NavigationSection( title="User Management", separator=True, items=[ NavigationItem(title="Users", icon=Icons.PEOPLE, link="admin:auth_user_changelist"), NavigationItem(title="Profiles", icon=Icons.ACCOUNT_CIRCLE, link="admin:profiles_profile_changelist"), ], ), ], )

Separators

Add visual separators between sections:

NavigationSection( title="Section Name", separator=True, # Adds separator above section items=[...], )

Icons

Use Icons constants from django_cfg:

from django_cfg import Icons, NavigationItem NavigationItem(title="Dashboard", icon=Icons.DASHBOARD, link="admin:index")

Common icons:

  • Icons.DASHBOARD - Dashboard/overview
  • Icons.ARTICLE - Blog posts/content
  • Icons.INVENTORY - Products/items
  • Icons.SHOPPING_CART - Orders/cart
  • Icons.PEOPLE - Users
  • Icons.SETTINGS - Settings
  • Icons.ANALYTICS - Analytics/reports

Collapsible Sections

Create expandable sections:

NavigationSection( title="Reports", collapsible=True, items=[ NavigationItem(title="Sales Report", link="admin:reports_sales_changelist"), NavigationItem(title="User Report", link="admin:reports_users_changelist"), ], )

Model Admin Customization

Basic Admin Registration

# apps/blog/admin.py from django.contrib import admin from unfold.admin import ModelAdmin from .models import Post, Comment @admin.register(Post) class PostAdmin(ModelAdmin): list_display = ['title', 'author', 'status', 'created_at'] list_filter = ['status', 'created_at'] search_fields = ['title', 'content'] date_hierarchy = 'created_at' fieldsets = ( ('Content', { 'fields': ('title', 'content', 'status') }), ('Metadata', { 'fields': ('author', 'created_at', 'updated_at'), 'classes': ('collapse',) }), ) readonly_fields = ['created_at', 'updated_at']

List Display Customization

@admin.register(Order) class OrderAdmin(ModelAdmin): list_display = [ 'id', 'user_email', 'total_amount', 'status_badge', 'created_at' ] def user_email(self, obj): return obj.user.email user_email.short_description = 'Customer' def total_amount(self, obj): return f"${obj.total:,.2f}" total_amount.short_description = 'Total' def status_badge(self, obj): colors = { 'pending': 'warning', 'processing': 'info', 'completed': 'success', 'cancelled': 'danger' } return f'<span class="badge badge-{colors[obj.status]}">{obj.status}</span>' status_badge.short_description = 'Status' status_badge.allow_tags = True

Inline Editing

class OrderItemInline(admin.TabularInline): model = OrderItem extra = 1 fields = ['product', 'quantity', 'price'] @admin.register(Order) class OrderAdmin(ModelAdmin): inlines = [OrderItemInline]

Actions

Add custom bulk actions:

@admin.register(Post) class PostAdmin(ModelAdmin): actions = ['publish_posts', 'unpublish_posts'] def publish_posts(self, request, queryset): updated = queryset.update(status='published') self.message_user( request, f'{updated} post(s) published successfully.' ) publish_posts.short_description = 'Publish selected posts' def unpublish_posts(self, request, queryset): updated = queryset.update(status='draft') self.message_user( request, f'{updated} post(s) unpublished.' ) unpublish_posts.short_description = 'Unpublish selected posts'

Advanced Features

Tabbed Interface

Organize fields in tabs:

@admin.register(Product) class ProductAdmin(ModelAdmin): fieldsets = ( ('Basic Information', { 'fields': ('name', 'description', 'category') }), ('Pricing', { 'fields': ('price', 'discount_price', 'tax_rate') }), ('Inventory', { 'fields': ('stock', 'reorder_level', 'supplier') }), ('Media', { 'fields': ('image', 'gallery') }), )

Filters

Add sidebar filters:

@admin.register(Post) class PostAdmin(ModelAdmin): list_filter = [ 'status', 'created_at', ('author', admin.RelatedFieldListFilter), ]

Configure search functionality:

@admin.register(Product) class ProductAdmin(ModelAdmin): search_fields = [ 'name', 'description', 'sku', 'category__name' ]

Autocomplete

Enable autocomplete for foreign keys:

@admin.register(Post) class PostAdmin(ModelAdmin): autocomplete_fields = ['author', 'category'] @admin.register(User) class UserAdmin(ModelAdmin): search_fields = ['email', 'first_name', 'last_name']
from django_cfg import UnfoldConfig, UnfoldSidebar UnfoldConfig( sidebar=UnfoldSidebar( show_search=True, # Enable search box show_all_applications=False, # Hide ungrouped apps ), )

Enable global search in sidebar:

sidebar=UnfoldSidebar( show_search=True, )

Users can search for:

  • Model names
  • Navigation items
  • Recent actions

Accessing the Admin

Login

Visit http://127.0.0.1:8000/admin/

Creating Superuser

Create additional admin users:

# Interactive prompt python manage.py createsuperuser # With credentials python manage.py createsuperuser \ --email [email protected] \ --noinput

Permissions

Control admin access:

@admin.register(Post) class PostAdmin(ModelAdmin): def has_delete_permission(self, request, obj=None): # Only superusers can delete return request.user.is_superuser def get_queryset(self, request): # Users only see their own posts qs = super().get_queryset(request) if request.user.is_superuser: return qs return qs.filter(author=request.user)

Best Practices

1. Organize Navigation Logically

Group related items together using NavigationSection:

# ✅ Good: Logical grouping navigation=[ NavigationSection(title="Content", separator=True, items=[...]), NavigationSection(title="E-Commerce", separator=True, items=[...]), NavigationSection(title="Users", separator=True, items=[...]), ] # ❌ Bad: Random order or raw dicts navigation=[ {"title": "Orders", ...}, # Wrong: use NavigationSection objects ]

2. Use Meaningful Dashboard Metrics

Show actionable business metrics:

# ✅ Good: Actionable metrics { "title": "Orders Today", "value": "23", "description": "+12% vs yesterday" } # ❌ Bad: Meaningless numbers { "title": "Database Records", "value": "1,234,567" }

3. Customize List Displays

Make lists informative and scannable:

# ✅ Good: Relevant information list_display = ['title', 'author', 'status', 'views', 'created_at'] # ❌ Bad: Too much or too little list_display = ['id']

4. Add Helpful Actions

Provide bulk operations:

# ✅ Good: Common operations actions = ['publish_posts', 'archive_posts', 'export_csv'] # ❌ Bad: Only default delete action

A well-designed admin interface improves productivity and user experience!

Last updated on