django-admin

SKILL.md

Django Admin Customization

You are a Django admin expert. Your goal is to configure the admin site to be maximally useful for content management and operations.

Initial Assessment

Check for project context first: If .agents/django-project-context.md exists, read it for the project's key models and any existing admin conventions.


Basic Registration

# articles/admin.py
from django.contrib import admin
from .models import Article, Tag, Comment

# Simple registration
admin.site.register(Tag)

# Customized registration
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    pass

List View Customization

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    # Columns shown in the list
    list_display = ['title', 'author', 'status', 'created_at', 'is_featured']

    # Clickable column to open detail (default: first field)
    list_display_links = ['title']

    # Editable columns directly in list view
    list_editable = ['status']

    # Sidebar filters
    list_filter = ['status', 'created_at', 'author']

    # Search bar (searches these fields)
    search_fields = ['title', 'content', 'author__email']

    # Default ordering
    ordering = ['-created_at']

    # Number of items per page
    list_per_page = 25

    # Add computed column
    @admin.display(description='Featured', boolean=True, ordering='is_featured')
    def is_featured(self, obj):
        return obj.status == Article.Status.PUBLISHED and obj.featured

Detail View Customization

Fieldsets

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {
            'fields': ['title', 'slug', 'content'],
        }),
        ('Publishing', {
            'fields': ['status', 'author', 'published_at'],
        }),
        ('Metadata', {
            'fields': ['tags', 'featured'],
            'classes': ['collapse'],  # Collapsible section
        }),
    ]
    prepopulated_fields = {'slug': ('title',)}  # Auto-fill slug from title
    readonly_fields = ['created_at', 'updated_at']
    autocomplete_fields = ['author']             # Foreign key with search
    filter_horizontal = ['tags']                 # M2M widget
    # or:
    filter_vertical = ['tags']
    raw_id_fields = ['author']                   # ID input (faster for large tables)
    date_hierarchy = 'created_at'                # Date drill-down nav

Inline Models

TabularInline (Compact rows)

class CommentInline(admin.TabularInline):
    model = Comment
    extra = 0               # No extra empty forms
    max_num = 10
    readonly_fields = ['created_at', 'author']
    fields = ['author', 'content', 'created_at']
    show_change_link = True  # Link to comment's own admin page

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    inlines = [CommentInline]

StackedInline (Vertical layout — for complex forms)

class ProfileInline(admin.StackedInline):
    model = Profile
    extra = 0
    can_delete = False

Custom Actions

from django.contrib import admin, messages

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    actions = ['publish_selected', 'archive_selected']

    @admin.action(description='Publish selected articles')
    def publish_selected(self, request, queryset):
        count = queryset.update(status=Article.Status.PUBLISHED)
        self.message_user(request, f'{count} article(s) published.', messages.SUCCESS)

    @admin.action(description='Archive selected articles')
    def archive_selected(self, request, queryset):
        count = queryset.update(status=Article.Status.ARCHIVED)
        self.message_user(request, f'{count} article(s) archived.')

Custom User Admin

When you have a custom User model:

from django.contrib.auth.admin import UserAdmin
from .models import User

@admin.register(User)
class CustomUserAdmin(UserAdmin):
    # Add your custom fields to the fieldsets
    fieldsets = UserAdmin.fieldsets + (
        ('Profile', {'fields': ('bio', 'avatar')}),
    )
    add_fieldsets = UserAdmin.add_fieldsets + (
        ('Profile', {'fields': ('bio',)}),
    )
    list_display = ['email', 'username', 'is_staff', 'is_active', 'created_at']
    list_filter = ['is_staff', 'is_active', 'groups']
    search_fields = ['email', 'username', 'first_name', 'last_name']

Admin Permissions Per Model

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    def has_delete_permission(self, request, obj=None):
        return request.user.is_superuser  # Only superusers can delete

    def has_add_permission(self, request):
        return request.user.has_perm('articles.add_article')

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(author=request.user)  # Editors see only their own

Admin Site Branding

# admin.py or apps.py
admin.site.site_header = 'My App Administration'
admin.site.site_title = 'My App Admin'
admin.site.index_title = 'Dashboard'

Performance in Admin

Always optimize queries for list views:

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    list_select_related = ['author']   # Auto select_related for list
    # Or manually:
    def get_queryset(self, request):
        return super().get_queryset(request).select_related('author').prefetch_related('tags')

Related Skills

  • django-models: The models being administered
  • django-auth: Custom User model admin configuration
  • django-performance: Optimizing admin querysets for large tables
Weekly Installs
3
First Seen
5 days ago
Installed on
amp3
cline3
opencode3
cursor3
kimi-cli3
codex3