Переопределение шаблонов и стилей Django Admin
Как изменить внешний вид Django Admin без патчинга ядра: base_site.html, блоки branding и extrastyle, CSS-переменные, тёмная тема и шаблоны моделей.
Содержание · 12 разделов
- Что можно изменить без шаблонов
- Как Django находит шаблоны админки
- Какие шаблоны и блоки переопределять
- Логотип и название в шапке
- Цвета через CSS-переменные
- Тёмная тема
- Изменения для одной модели
- Статика в продакшне
- Чего делать не нужно
- Частые ошибки
- Шаблон не применяется
- Стили не применяются
- В тёмной теме остались светлые цвета
- Пропали стили страницы списка или дашборда
- Частые вопросы
- Как заменить фавикон админки?
- Как изменить страницу входа?
- Как добавить свою ссылку в шапку?
- Как отличить тестовую админку от рабочей?
- Итог
Внешний вид Django Admin меняется без правки исходников Django. Шаблоны админки можно переопределить по одному, а цвета задаются CSS-переменными. Достаточно положить свои файлы туда, где Django найдёт их раньше встроенных.
Коротко: создайте templates/admin/base_site.html со строкой {% extends "admin/base_site.html" %}. В блоке branding замените логотип и название, а в блоке extrastyle подключите свой CSS, где переопределены переменные --primary, --secondary, --header-bg и другие. Примеры проверены на Django 5.2 LTS и 6.x; отличия Django 4.2 отмечены отдельно.
Что можно изменить без шаблонов
Тексты в шапке и заголовках задаются атрибутами сайта админки. Шаблоны для этого не нужны:
# shop/admin.py (любой admin.py проекта)
from django.contrib import admin
admin.site.site_header = "Acme: управление" # шапка и страница входа
admin.site.site_title = "Acme Admin" # окончание <title> во вкладке
admin.site.index_title = "Разделы" # заголовок главной страницы
admin.site.site_url = "https://acme.example/" # ссылка «Открыть сайт»
| Атрибут | Где виден | По умолчанию |
|---|---|---|
site_header | шапка всех страниц, форма входа | «Администрирование Django» |
site_title | заголовок вкладки браузера | «Административный сайт Django» |
index_title | H1 на главной странице | «Администрирование сайта» |
site_url | ссылка «Открыть сайт», None скрывает её | "/" |
enable_nav_sidebar | боковая панель с моделями | True |
Если этого мало, переходите к шаблонам.
Как Django находит шаблоны админки
Встроенные шаблоны лежат в django/contrib/admin/templates/admin/. Django ищет шаблон по имени в таком порядке:
- каталоги из
TEMPLATES["DIRS"]; - папки
templates/приложений в порядкеINSTALLED_APPS(приAPP_DIRS: True).
Отсюда два рабочих варианта. Первый: общая папка проекта.
# settings.py
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"], # здесь лежит templates/admin/...
"APP_DIRS": True,
"OPTIONS": {"context_processors": [...]},
},
]
Второй: шаблоны лежат в приложении admin_theme/templates/admin/, и это приложение стоит выше django.contrib.admin:
INSTALLED_APPS = [
"admin_theme", # должен быть раньше django.contrib.admin
"django.contrib.admin",
"django.contrib.auth",
# ...
]
Свой шаблон почти никогда не нужно копировать целиком. Начните файл с {% extends "admin/base_site.html" %}, даже если он сам называется admin/base_site.html. Django пропустит текущий файл и унаследует встроенный, а вы переопределите только нужные блоки. Так обновления Django не ломают вашу тему.
Какие шаблоны и блоки переопределять
Всё оформление админки наследуется от admin/base.html через admin/base_site.html. Основные блоки:
| Блок | Шаблон | Для чего |
|---|---|---|
branding | base_site.html | логотип и название в шапке |
title | base_site.html | содержимое <title> |
extrastyle | base.html | дополнительные CSS после стандартных |
extrahead | base.html | скрипты, мета-теги, шрифты |
dark-mode-vars | base.html | подключение dark_mode.css и theme.js |
userlinks | base.html | ссылки справа в шапке: документация, смена пароля, выход |
nav-global | base_site.html | пустое место в шапке под свою навигацию |
footer | base.html | подвал страницы |
Шаблоны страниц можно переопределить не только для всей админки, но и для отдельного приложения или модели. Django ищет, например, сначала admin/<app_label>/<model_name>/change_form.html, затем admin/<app_label>/change_form.html и только потом admin/change_form.html. Так работают change_form.html, change_list.html, delete_confirmation.html, object_history.html, app_index.html, а также фрагменты submit_line.html, pagination.html, search_form.html, actions.html и другие. Шаблоны index.html и login.html переопределяются только для всего сайта.
Логотип и название в шапке
Переопределите блок branding. Разметку берите из base_site.html вашей версии Django и меняйте только нужное:
{# templates/admin/base_site.html #}
{% extends "admin/base_site.html" %}
{% load static %}
{% block extrastyle %}{{ block.super }}
<link rel="stylesheet" href="{% static 'admin_theme/brand.css' %}">
{% endblock %}
{% block branding %}
<div id="site-name">
<a href="{% url 'admin:index' %}" class="brand">
<img src="{% static 'admin_theme/logo.svg' %}" alt="" width="28" height="28">
{{ site_header|default:_('Django administration') }}
</a>
</div>
{% if user.is_anonymous %}
{% include "admin/color_theme_toggle.html" %}
{% endif %}
{% endblock %}
{% block footer %}
<div class="brand-footer">Acme · <a href="mailto:it@example.com">поддержка</a></div>
{% endblock %}
Обратите внимание на детали:
{% load static %}нужен в каждом шаблоне, где есть тегstatic: загрузка из родительского шаблона не наследуется.- Фильтр
defaultвsite_headerнужен для страниц, которые используют шаблоны админки без её контекста. Например, это стандартные страницы сброса пароля. - Переключатель темы для неавторизованного пользователя (страница входа) в оригинале выводится внутри
branding. Если его не повторить, он пропадёт со страницы входа. - В Django 4.2 название обёрнуто в
<h1 id="site-name">, с Django 5.0 — в<div id="site-name">. Стили админки привязаны к этой разметке, поэтому сверяйтесь со своей версией.
Логотип и CSS кладите в static/ приложения, например в admin_theme/static/admin_theme/. Не называйте свою папку admin/, чтобы не перекрыть встроенную статику.
Цвета через CSS-переменные
С Django 3.2 стили админки построены на CSS-переменных. Их значения объявлены в начале файла django/contrib/admin/static/admin/css/base.css. Перекрасить админку — значит переопределить переменные в своём файле, который подключается в extrastyle после стандартных стилей:
/* admin_theme/static/admin_theme/brand.css */
html[data-theme='light'],
:root {
--primary: #a5b4fc;
--secondary: #3730a3;
--accent: #fde68a;
--primary-fg: #fff;
--header-bg: #1e1b4b;
--header-color: #e0e7ff;
--breadcrumbs-bg: #312e81;
--link-fg: #4338ca;
--link-hover-color: #312e81;
--button-bg: #3730a3;
--button-hover-bg: #312e81;
--default-button-bg: #4f46e5;
--default-button-hover-bg: #3730a3;
--font-family-primary: 'Inter', system-ui, sans-serif;
}
#site-name .brand {
display: inline-flex;
align-items: center;
gap: 10px;
}
Селектор html[data-theme='light'], :root повторяет тот, что использует сама Django. Почему это важно, разберём в разделе о тёмной теме.
Ключевые переменные:
| Переменная | Что окрашивает |
|---|---|
--primary | светлый фирменный цвет, фоны выделенных элементов |
--secondary | основной тёмный цвет; в Django 5.x от него по умолчанию считаются шапка и кнопки |
--accent | ссылка с названием сайта в шапке |
--header-bg, --header-color | фон и текст шапки |
--breadcrumbs-bg | фон «хлебных крошек» |
--link-fg, --link-hover-color | цвет ссылок |
--button-bg, --default-button-bg | обычные кнопки и главная кнопка «Сохранить» |
--body-bg, --body-fg | фон и текст страницы |
--font-family-primary | основной шрифт |
Важно: связи между переменными меняются от версии к версии. Например, заголовки модулей (
.module h2) в Django 4.2 окрашены через--primary, а в 5.x — через--header-bg. Перед настройкой откройтеbase.cssсвоей версии и найдите, где используется нужная переменная.
Шрифт из --font-family-primary нужно ещё подключить. Для этого добавьте <link> на файл шрифта в блок extrahead или extrastyle.
Тёмная тема
Тёмная тема появилась в Django 3.2. С версии 4.2 в шапке есть переключатель «светлая / тёмная / как в системе». Устроено это так:
- файл
admin/css/dark_mode.cssподключается в блокеdark-mode-varsи переопределяет переменные внутри@media (prefers-color-scheme: dark)и дляhtml[data-theme="dark"]; - скрипт
theme.jsхранит выбор пользователя вlocalStorageи ставит на<html>атрибутdata-themeсо значениемauto,lightилиdark.
Ваш brand.css загружается позже dark_mode.css. Правило :root с теми же переменными перебьёт тёмные значения, и при системной тёмной теме админка останется светлой. Поэтому задайте тёмные значения явно, в тех же двух местах, что и Django:
/* продолжение brand.css */
@media (prefers-color-scheme: dark) {
:root {
--primary: #312e81;
--link-fg: #a5b4fc;
--link-hover-color: #c7d2fe;
}
}
html[data-theme='dark'] {
--primary: #312e81;
--link-fg: #a5b4fc;
--link-hover-color: #c7d2fe;
}
Благодаря селектору html[data-theme='light'] в светлом блоке явный выбор «светлая» побеждает тёмный медиазапрос: у этого селектора выше специфичность, чем у :root.
Если тёмная тема не нужна вовсе, отключите её двумя изменениями. Добавьте в templates/admin/base_site.html пустой блок {% block dark-mode-vars %}{% endblock %} и создайте пустой файл templates/admin/color_theme_toggle.html, чтобы убрать кнопку переключения.
Изменения для одной модели
Предупреждение на форме оплаченного заказа не требует трогать другие страницы. Создайте templates/admin/shop/order/change_form.html, где shop — метка приложения, а order — имя модели в нижнем регистре:
{% extends "admin/change_form.html" %}
{% block form_top %}
{{ block.super }}
{% if original.status == "paid" %}
<p class="errornote">Заказ уже оплачен: изменение суммы не вернёт деньги покупателю.</p>
{% endif %}
{% endblock %}
В контексте формы изменения объект доступен как original. Вместо соглашения об именах можно явно указать шаблон в ModelAdmin:
@admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
change_form_template = "admin/shop/order_change_form.html"
Так же работают change_list_template, add_form_template, delete_confirmation_template и object_history_template. У прокси-модели свой model_name, поэтому шаблон основной модели к ней не применяется. Пример с графиком в шаблоне списка разобран в статье «Графики и отчёты в Django Admin», а виджеты на главной странице — в материале про дашборд Django Admin.
Статика в продакшне
Новые CSS и картинки попадут на сервер только после python manage.py collectstatic. Если стили не обновляются у пользователей после выкладки, виноват кеш браузера. Хранилище ManifestStaticFilesStorage добавляет хеш содержимого к имени файла (brand.3f2a….css), и браузер получает новую версию при каждом изменении:
# settings.py (Django 4.2+)
STORAGES = {
"default": {"BACKEND": "django.core.files.storage.FileSystemStorage"},
"staticfiles": {
"BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
},
}
Как раздавать статику через Nginx, описано в руководстве по деплою Django с Gunicorn и Nginx.
Чего делать не нужно
- Править файлы в
site-packages/django/. Изменения пропадут при первом жеpip install -U djangoи не попадут на другие машины. - Копировать
base.htmlцеликом. Вы зафиксируете разметку старой версии и потеряете исправления из новых. Переопределяйте блоки черезextends. - Подменять
admin/css/base.cssфайлом с тем же путём. Технически это работает, но тянет те же проблемы, что и копирование шаблонов. Достаточно переопределить переменные. - Ставить
!importantповсюду. Ваш CSS и так подключается последним. Если правило не срабатывает, проверьте специфичность селектора.
Если перекраски мало и нужен другой интерфейс с боковым меню, вкладками и дашбордом, посмотрите на готовые темы. Их сравнение — в обзоре Unfold, Jazzmin и Grappelli.
Частые ошибки
Шаблон не применяется
Проверьте путь templates/admin/base_site.html: подпапка admin/ обязательна. Если шаблон лежит в приложении, оно должно стоять в INSTALLED_APPS выше django.contrib.admin. Если в папке проекта, она должна быть указана в TEMPLATES["DIRS"]. После создания нового каталога шаблонов перезапустите сервер.
Стили не применяются
Откройте вкладку Network в инструментах разработчика. 404 на brand.css означает неверный путь в {% static %} или забытый collectstatic. Если файл загружается, но цвет не меняется, найдите в base.css своей версии, какая переменная на самом деле отвечает за этот элемент.
В тёмной теме остались светлые цвета
Вы переопределили переменные только в :root. Добавьте тёмные значения в @media (prefers-color-scheme: dark) и в html[data-theme='dark'], как в примере выше.
Пропали стили страницы списка или дашборда
Вы переопределили extrastyle без {{ block.super }}. В base_site.html это безопасно, потому что в base.html блок пуст. Но в change_list.html, change_form.html и index.html через этот блок подключаются стили страницы, и без {{ block.super }} они пропадут.
Частые вопросы
Как заменить фавикон админки?
Добавьте ссылку на иконку в блок extrahead того же templates/admin/base_site.html:
{% block extrahead %}{{ block.super }}
<link rel="icon" href="{% static 'admin_theme/favicon.svg' %}" type="image/svg+xml">
{% endblock %}
Как изменить страницу входа?
Логотип и стили из base_site.html применяются и к ней. Чтобы добавить текст, создайте templates/admin/login.html и расширьте блок content:
{# templates/admin/login.html #}
{% extends "admin/login.html" %}
{% block content %}
<p class="help">Вход только для сотрудников Acme. Забыли пароль — напишите на it@example.com.</p>
{{ block.super }}
{% endblock %}
Как добавить свою ссылку в шапку?
Переопределите блок userlinks и сохраните стандартные ссылки через {{ block.super }}:
{% block userlinks %}
<a href="https://wiki.example.com/admin-help">Инструкция</a> /
{{ block.super }}
{% endblock %}
Как отличить тестовую админку от рабочей?
Проще всего — разные заголовки. Задайте site_header по переменной окружения, а для заметности добавьте в тестовом окружении отдельный CSS с другим --header-bg:
# shop/admin.py
import os
from django.contrib import admin
env = os.environ.get("APP_ENV", "production")
if env != "production":
admin.site.site_header = f"Acme: {env.upper()}"
Итог
Внешний вид Django Admin меняется в трёх местах. Атрибуты site_header и site_title отвечают за тексты, переопределённый admin/base_site.html с блоками branding и extrastyle — за логотип и подключение стилей, CSS-переменные — за цвета светлой и тёмной темы. Для отдельных моделей используйте шаблоны вида admin/<app>/<model>/change_form.html.
Остальные настройки админки собраны в полном руководстве по Django Admin. Все статьи раздела — на странице Django Admin.
- #Django Admin
- #Шаблоны Admin
- #CSS
- #Темизация
- #Кастомизация Admin