Django's admin interface comes built-in but requires some initial setup. This chapter covers everything you need to know to get the admin interface up and running.
The admin app is included by default in INSTALLED_APPS:
# settings.py
INSTALLED_APPS = [
'django.contrib.admin', # Admin interface
'django.contrib.auth', # Authentication system
'django.contrib.contenttypes', # Content types framework
'django.contrib.sessions', # Session framework
'django.contrib.messages', # Messaging framework
'django.contrib.staticfiles', # Static files handling
# Your apps here
]
Add admin URLs to your project's URL configuration:
# urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
# Your other URL patterns
]
Create the necessary database tables:
python manage.py migrate
Create an admin user account:
python manage.py createsuperuser
You'll be prompted to enter:
# settings.py
# Admin site configuration
ADMIN_URL = 'admin/' # Change this for security
# Admin site headers and titles
ADMIN_SITE_HEADER = 'My Site Administration'
ADMIN_SITE_TITLE = 'My Site Admin'
ADMIN_INDEX_TITLE = 'Welcome to My Site Administration'
# Date and time formatting
USE_L10N = True
USE_TZ = True
TIME_ZONE = 'UTC'
# Language settings
LANGUAGE_CODE = 'en-us'
USE_I18N = True
Create a custom admin site for more control:
# admin.py
from django.contrib import admin
from django.contrib.admin import AdminSite
from django.urls import path
class MyAdminSite(AdminSite):
"""Custom admin site"""
site_header = 'My Custom Administration'
site_title = 'My Admin'
index_title = 'Welcome to My Administration'
def get_urls(self):
"""Add custom URLs to admin"""
urls = super().get_urls()
custom_urls = [
path('custom-view/', self.admin_view(self.custom_view), name='custom_view'),
]
return custom_urls + urls
def custom_view(self, request):
"""Custom admin view"""
from django.shortcuts import render
context = {
'title': 'Custom Admin View',
'site_header': self.site_header,
}
return render(request, 'admin/custom_view.html', context)
# Create custom admin site instance
admin_site = MyAdminSite(name='myadmin')
# Use in URLs
# urls.py
from myapp.admin import admin_site
urlpatterns = [
path('admin/', admin_site.urls),
]
Override admin templates by creating them in your templates directory:
<!-- templates/admin/base_site.html -->
{% extends "admin/base.html" %}
{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
<h1 id="site-name">
<a href="{% url 'admin:index' %}">
<img src="{% load static %}{% static 'admin/img/logo.png' %}" alt="Logo" height="40">
My Site Administration
</a>
</h1>
{% endblock %}
{% block nav-global %}{% endblock %}
Add custom styling to the admin:
# admin.py
class MyModelAdmin(admin.ModelAdmin):
class Media:
css = {
'all': ('admin/css/custom.css',)
}
js = ('admin/js/custom.js',)
/* static/admin/css/custom.css */
#header {
background: #2c3e50;
}
#branding h1 {
color: #ecf0f1;
}
.module h2, .module caption, .inline-group h2 {
background: #34495e;
}
Change the admin URL for security:
# urls.py
from django.contrib import admin
from django.urls import path
import os
# Use environment variable for admin URL
admin_url = os.environ.get('ADMIN_URL', 'admin/')
urlpatterns = [
path(admin_url, admin.site.urls),
]
Restrict admin access by IP address:
# middleware.py
from django.http import HttpResponseForbidden
from django.conf import settings
import ipaddress
class AdminIPRestrictionMiddleware:
"""Restrict admin access to specific IP addresses"""
def __init__(self, get_response):
self.get_response = get_response
self.allowed_ips = getattr(settings, 'ADMIN_ALLOWED_IPS', [])
def __call__(self, request):
if request.path.startswith('/admin/'):
client_ip = self.get_client_ip(request)
if not self.is_ip_allowed(client_ip):
return HttpResponseForbidden('Access denied')
return self.get_response(request)
def get_client_ip(self, request):
"""Get client IP address"""
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
def is_ip_allowed(self, ip):
"""Check if IP is in allowed list"""
if not self.allowed_ips:
return True # No restrictions if list is empty
try:
client_ip = ipaddress.ip_address(ip)
for allowed_ip in self.allowed_ips:
if client_ip in ipaddress.ip_network(allowed_ip, strict=False):
return True
except ValueError:
pass
return False
# settings.py
MIDDLEWARE = [
# ... other middleware
'myapp.middleware.AdminIPRestrictionMiddleware',
]
# Allowed IP addresses/networks
ADMIN_ALLOWED_IPS = [
'192.168.1.0/24', # Local network
'10.0.0.1', # Specific IP
]
# settings/development.py
from .base import *
# Admin configuration for development
ADMIN_URL = 'admin/'
DEBUG = True
# Allow all IPs in development
ADMIN_ALLOWED_IPS = []
# Admin site customization
ADMIN_SITE_HEADER = 'My Site Admin (Development)'
# settings/production.py
from .base import *
import os
# Secure admin configuration
ADMIN_URL = os.environ.get('ADMIN_URL', 'secure-admin-panel/')
DEBUG = False
# Restrict admin access
ADMIN_ALLOWED_IPS = [
'203.0.113.0/24', # Office network
]
# Production admin customization
ADMIN_SITE_HEADER = 'My Site Administration'
# Additional security
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
Django automatically logs admin actions, but you can customize this:
# models.py
from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
from django.contrib.contenttypes.models import ContentType
def log_admin_action(user, obj, action_flag, change_message=''):
"""Log custom admin action"""
LogEntry.objects.log_action(
user_id=user.id,
content_type_id=ContentType.objects.get_for_model(obj).pk,
object_id=obj.pk,
object_repr=str(obj),
action_flag=action_flag,
change_message=change_message
)
# Usage in views or admin methods
log_admin_action(
user=request.user,
obj=my_object,
action_flag=CHANGE,
change_message='Custom action performed'
)
# admin.py
from django.contrib.admin.models import LogEntry
from django.contrib import admin
@admin.register(LogEntry)
class LogEntryAdmin(admin.ModelAdmin):
"""Admin interface for viewing admin logs"""
list_display = [
'action_time',
'user',
'content_type',
'object_repr',
'action_flag',
'change_message'
]
list_filter = [
'action_time',
'user',
'content_type',
'action_flag'
]
search_fields = [
'object_repr',
'change_message'
]
readonly_fields = [
'action_time',
'user',
'content_type',
'object_id',
'object_repr',
'action_flag',
'change_message'
]
def has_add_permission(self, request):
return False
def has_change_permission(self, request, obj=None):
return False
def has_delete_permission(self, request, obj=None):
return False
# admin.py
class OptimizedModelAdmin(admin.ModelAdmin):
"""Optimized admin with efficient queries"""
def get_queryset(self, request):
"""Optimize queryset with select_related and prefetch_related"""
queryset = super().get_queryset(request)
return queryset.select_related(
'user',
'category'
).prefetch_related(
'tags',
'comments'
)
def get_list_display(self, request):
"""Dynamic list display based on user permissions"""
list_display = ['title', 'user', 'created_at']
if request.user.has_perm('myapp.view_advanced_fields'):
list_display.extend(['status', 'priority'])
return list_display
# admin.py
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
@method_decorator(cache_page(60 * 15), name='changelist_view') # 15 minutes
class CachedModelAdmin(admin.ModelAdmin):
"""Admin with cached changelist view"""
def changelist_view(self, request, extra_context=None):
"""Cached changelist view"""
return super().changelist_view(request, extra_context)
# tests.py
from django.test import TestCase, Client
from django.contrib.auth.models import User
from django.urls import reverse
class AdminTestCase(TestCase):
"""Test admin interface"""
def setUp(self):
self.client = Client()
self.superuser = User.objects.create_superuser(
username='admin',
email='admin@example.com',
password='testpass123'
)
def test_admin_login(self):
"""Test admin login"""
response = self.client.post(reverse('admin:login'), {
'username': 'admin',
'password': 'testpass123'
})
self.assertEqual(response.status_code, 302)
def test_admin_access(self):
"""Test admin access after login"""
self.client.login(username='admin', password='testpass123')
response = self.client.get(reverse('admin:index'))
self.assertEqual(response.status_code, 200)
def test_model_admin_access(self):
"""Test model admin access"""
self.client.login(username='admin', password='testpass123')
response = self.client.get(reverse('admin:myapp_mymodel_changelist'))
self.assertEqual(response.status_code, 200)
# settings.py
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# For development
if DEBUG:
from django.conf.urls.static import static
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
# Collect static files
python manage.py collectstatic
# Clear browser cache
# Check STATIC_URL and STATIC_ROOT settings
# Verify static files middleware is installed
# Check user permissions
user.is_staff = True # Required for admin access
user.is_superuser = True # Full admin access
user.save()
# Or assign specific permissions
from django.contrib.auth.models import Permission
permission = Permission.objects.get(codename='add_mymodel')
user.user_permissions.add(permission)
Now that you have the admin interface enabled and configured, let's learn how to register your models and make them available in the admin interface.
Admin Site
Django's admin interface is one of its most powerful features, providing a ready-to-use administrative interface for your models. It's designed to be used by non-technical users to manage content and data, making it an essential tool for content management and site administration.
Registering Models
To make your models available in the Django admin interface, you need to register them. This chapter covers various ways to register models and basic configuration options.