Django Admin Styling
Introduction
The Django Admin interface provides a powerful out-of-the-box solution for managing your application's data. While the default styling is functional, you may want to customize its appearance to match your project's branding or improve the user experience for administrators. In this tutorial, we'll explore various techniques to style and customize the Django Admin interface.
Understanding Django Admin Templates
Django's admin interface is built using Django's template system. The admin templates are located in the Django source code, but you can override them in your project. Before diving into styling, it's important to understand the template hierarchy.
Default Admin Template Structure
The admin templates are located within Django's installation directory, typically at:
django/contrib/admin/templates/admin/
Common templates include:
base_site.html
- The main template for the admin siteindex.html
- The admin homepagechange_list.html
- List view of model instanceschange_form.html
- Form for adding/editing model instances
Basic Admin Customization
1. Changing the Admin Site Title and Header
The simplest customization is changing the admin site title and header. You can do this in your project's admin.py
:
from django.contrib import admin
# Customize admin site title and header
admin.site.site_header = "My Project Admin"
admin.site.site_title = "My Project Admin Portal"
admin.site.index_title = "Welcome to My Project Admin Portal"
Result: This changes the text in the admin interface from "Django Administration" to your custom titles.
2. Creating a Custom base_site.html
To make more substantial changes to the admin interface, create a custom base_site.html
:
- Create the directory structure in your project:
your_project/
templates/
admin/
base_site.html
- Add the template directory to your
TEMPLATES
setting insettings.py
:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')], # Add this line
'APP_DIRS': True,
# ... other settings
},
]
- Create your custom
base_site.html
:
{% extends "admin/base.html" %}
{% load static %}
{% block title %}{{ title }} | {{ site_title|default:_('My Custom Admin') }}{% endblock %}
{% block branding %}
<h1 id="site-name">
<a href="{% url 'admin:index' %}">
<img src="{% static 'img/logo.png' %}" height="40px" alt="Logo" />
{{ site_header|default:_('My Company Administration') }}
</a>
</h1>
{% endblock %}
{% block extrastyle %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% static 'css/admin-style.css' %}" />
{% endblock %}
Adding Custom CSS Styles
1. Create a Custom CSS File
Create a CSS file in your static directory:
your_project/
static/
css/
admin-style.css
Add your custom styles to admin-style.css
:
/* Primary branding colors */
:root {
--primary: #5b21b6;
--secondary: #8b5cf6;
--accent: #c4b5fd;
--dark-bg: #1f2937;
--light-text: #f9fafb;
}
/* Header styling */
#header {
background: var(--primary);
color: var(--light-text);
}
/* Link colors */
a:link, a:visited {
color: var(--secondary);
}
/* Button styling */
.button, input[type=submit], input[type=button], .submit-row input, a.button {
background: var(--primary);
color: var(--light-text);
}
.button:hover, input[type=submit]:hover, input[type=button]:hover {
background: var(--secondary);
}
/* Selected rows */
.selected {
background-color: var(--accent) !important;
}
/* Module styling */
.module h2, .module caption, .inline-group h2 {
background-color: var(--primary);
}
2. Configure Static Files
Make sure your settings.py
has the correct static files configuration:
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
Advanced Admin Styling
1. Custom Admin Theme with Django Jazzmin
For a more complete admin theme, consider using packages like Django Jazzmin. Install it with pip:
pip install django-jazzmin
Add it to your INSTALLED_APPS
in settings.py
(before django.contrib.admin
):
INSTALLED_APPS = [
'jazzmin',
# ... Django's default apps
'django.contrib.admin',
# ... your apps
]
Configure Jazzmin in your settings.py
:
JAZZMIN_SETTINGS = {
"site_title": "My Project Admin",
"site_header": "My Project",
"site_brand": "My Project",
"site_logo": "img/logo.png",
"login_logo": "img/login-logo.png",
"site_icon": "img/favicon.ico",
"welcome_sign": "Welcome to My Project Admin",
"copyright": "My Company Ltd",
"custom_css": "css/admin-style.css",
"custom_js": "js/admin-script.js",
"show_ui_builder": True,
"topmenu_links": [
{"name": "Home", "url": "admin:index", "permissions": ["auth.view_user"]},
{"name": "View Site", "url": "/", "new_window": True},
],
"usermenu_links": [
{
"name": "Support",
"url": "https://example.com/support/",
"new_window": True,
},
],
"icons": {
"auth.user": "fas fa-user",
"auth.group": "fas fa-users",
},
"default_icon_parents": "fas fa-folder",
"default_icon_children": "fas fa-file",
"themes": [
{
"theme": "default",
"color": "#5b21b6",
"dark_mode": False,
},
{
"theme": "darkly",
"color": "#8B5CF6",
"dark_mode": True,
},
],
}
2. Customizing Admin List Display
You can customize how model lists appear in the admin by using CSS classes in your ModelAdmin
classes:
from django.contrib import admin
from .models import Product
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ('name', 'price', 'stock_status')
list_display_links = ('name',)
def stock_status(self, obj):
if obj.stock <= 0:
return format_html('<span class="out-of-stock">Out of Stock</span>')
elif obj.stock < 10:
return format_html('<span class="low-stock">Low Stock ({0})</span>', obj.stock)
else:
return format_html('<span class="in-stock">In Stock ({0})</span>', obj.stock)
stock_status.short_description = 'Stock Status'
class Media:
css = {
'all': ('css/admin/product.css',)
}
Then, create static/css/admin/product.css
:
.out-of-stock {
color: #fff;
background-color: #dc2626;
padding: 3px 8px;
border-radius: 4px;
}
.low-stock {
color: #fff;
background-color: #f59e0b;
padding: 3px 8px;
border-radius: 4px;
}
.in-stock {
color: #fff;
background-color: #10b981;
padding: 3px 8px;
border-radius: 4px;
}
Practical Example: Building a Branded Admin Interface
Let's create a complete example of a branded admin interface for a fictional company called "GreenTech Solutions":
Step 1: Create the Basic Structure
Create the necessary directories and files:
your_project/
templates/
admin/
base_site.html
static/
admin/
css/
custom_admin.css
img/
greentech-logo.png
favicon.ico
Step 2: Customize base_site.html
{% extends "admin/base.html" %}
{% load static %}
{% block title %}{{ title }} | {{ site_title|default:_('GreenTech Admin') }}{% endblock %}
{% block extrahead %}
{{ block.super }}
<link rel="shortcut icon" href="{% static 'admin/img/favicon.ico' %}" />
{% endblock %}
{% block branding %}
<h1 id="site-name">
<a href="{% url 'admin:index' %}">
<img src="{% static 'admin/img/greentech-logo.png' %}" height="40px" alt="GreenTech Logo" />
<span>GreenTech Solutions Admin</span>
</a>
</h1>
{% endblock %}
{% block extrastyle %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/custom_admin.css' %}" />
{% endblock %}
{% block nav-global %}
<div class="admin-help-links">
<a href="https://docs.example.com" target="_blank">Documentation</a> |
<a href="https://support.example.com" target="_blank">Support</a>
</div>
{% endblock %}
Step 3: Create Custom CSS
In static/admin/css/custom_admin.css
:
:root {
--primary-color: #166534;
--secondary-color: #22c55e;
--light-green: #dcfce7;
--dark-text: #1e293b;
--light-text: #f8fafc;
}
/* Header styling */
#header {
background: var(--primary-color);
color: var(--light-text);
height: 70px;
padding: 10px 20px;
}
#header a:link, #header a:visited {
color: var(--light-text);
}
#site-name a {
display: flex;
align-items: center;
font-size: 20px;
}
#site-name img {
margin-right: 10px;
}
/* Module styling */
.module h2, .module caption, .inline-group h2 {
background-color: var(--primary-color);
}
/* Button styling */
.button, input[type=submit], input[type=button], .submit-row input, a.button {
background: var(--primary-color);
color: var(--light-text);
padding: 8px 15px;
border-radius: 4px;
}
.button:hover, input[type=submit]:hover, input[type=button]:hover {
background: var(--secondary-color);
}
.button.default, input[type=submit].default {
background: var(--secondary-color);
font-weight: bold;
}
.button.default:hover, input[type=submit].default:hover {
background: var(--primary-color);
}
/* Dashboard customization */
.dashboard .module table th {
background-color: var(--light-green);
color: var(--dark-text);
}
.dashboard .module table tr:nth-child(odd) {
background-color: #f9f9f9;
}
/* Login screen customization */
.login {
background: linear-gradient(135deg, var(--light-green), #f0fdf4);
}
.login #header {
background: transparent;
}
.login #header h1 {
color: var(--primary-color);
}
.admin-help-links {
float: right;
margin-right: 20px;
margin-top: -30px;
color: var(--light-text);
}
.admin-help-links a {
margin: 0 5px;
color: var(--light-text) !important;
}
/* Form styling */
fieldset.module {
border: 1px solid #e5e7eb;
border-radius: 6px;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
margin-bottom: 20px;
}
.form-row {
padding: 12px;
border-bottom: 1px solid #f1f1f1;
}
/* Make tables more readable */
table {
border-collapse: separate;
border-spacing: 0;
border-radius: 6px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
thead th {
background: var(--light-green);
color: var(--dark-text);
font-weight: 600;
}
/* Pagination */
.paginator a:link, .paginator a:visited {
background: var(--primary-color);
color: white;
padding: 4px 8px;
border-radius: 4px;
}
.paginator a:hover {
background: var(--secondary-color);
}
Step 4: Configure in Settings
Update your settings.py
:
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
STATIC_URL = '/static/'
# Admin site customization
ADMIN_SITE_HEADER = "GreenTech Solutions Admin"
ADMIN_SITE_TITLE = "GreenTech Admin Portal"
ADMIN_INDEX_TITLE = "Welcome to GreenTech Admin"
Step 5: Update urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
admin.site.site_header = settings.ADMIN_SITE_HEADER
admin.site.site_title = settings.ADMIN_SITE_TITLE
admin.site.index_title = settings.ADMIN_INDEX_TITLE
urlpatterns = [
path('admin/', admin.site.urls),
# ... your other URL patterns
]
Summary
In this tutorial, we've covered various ways to style and customize the Django admin interface:
- Basic customization - Changing titles, headers, and basic branding
- Template overriding - Creating custom admin templates
- CSS styling - Adding custom stylesheets to modify the admin appearance
- Third-party packages - Using packages like Django Jazzmin for comprehensive theming
- Practical example - Building a complete branded admin interface
Customizing the Django admin interface helps create a more cohesive user experience for administrators and can better reflect your project's branding. By using the techniques in this tutorial, you can transform the default admin interface into something that feels like an integral part of your application.
Additional Resources
- Django Admin Documentation
- Django Jazzmin Documentation
- Django Admin Bootstrap
- Django Grappelli - Another popular admin interface
Exercises
- Beginner: Customize the Django admin site title and header for your project.
- Intermediate: Create a custom CSS file to change the color scheme of the admin interface.
- Advanced: Override the
base_site.html
template to add your logo and custom navigation links. - Expert: Create a fully branded admin interface for a fictional company, including custom CSS, templates, and model admin customizations.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)