Кастомные страницы 404 и 500 в Django: с чего начать
За полчаса заменяете стандартные жёлто-серые страницы ошибок Django на свои. Разбираем, где включить, какие шаблоны создать и почему до продакшена вы их не увидите.

Пользователь заходит на несуществующий URL вашего сайта на Django и видит блёклую страницу с текстом «Not Found» и подписью про DEBUG. Смотрится как ошибка сервера, а не как часть сайта. К концу этого гайда у вас будут собственные страницы 404 и 500 — с вашим оформлением, меню и ссылкой на главную. На всё уйдёт минут 30, если проект уже запускается локально.
Инструкция написана для Django 5.x, но всё то же работает и в 4.2. Никакого дополнительного кода в Python писать почти не придётся: Django ищет шаблоны с конкретными именами сам.
Что нужно иметь до начала
- Работающий проект на Django, который запускается через
python manage.py runserver; - доступ к файлу
settings.pyи правам его редактировать; - папку для шаблонов, подключённую в настройках (обычно
templates/в корне проекта); - понимание, что при
DEBUG = Trueкастомные страницы не показываются — Django специально отдаёт технические страницы с трейсбеком. Это главная ловушка новичка, к ней вернёмся.
Шаг 1. Проверьте, где Django ищет шаблоны
Откройте settings.py и найдите список TEMPLATES. Django по умолчанию ищет шаблоны ошибок в корне любой директории шаблонов. Убедитесь, что папка подключена одним из двух способов.
Способ первый — общая папка в корне проекта:
# settings.py (Django 5.x)
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [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",
],
},
},
]Если DIRS пустой, добавьте туда BASE_DIR / "templates". Проверка: создайте файл templates/test.html и попробуйте отрендерить его из любой вью — если открывается, папка видна.
При APP_DIRS = True шаблоны можно положить и в папку templates/ любого приложения, но для страниц ошибок удобнее держать их в общей папке проекта — они относятся ко всему сайту, а не к одному приложению.
Шаг 2. Создайте шаблоны 404.html и 500.html
В корне папки шаблонов (не во вложенной подпапке) создайте два файла с точными именами: 404.html и 500.html. Имена жёстко зафиксированы во фреймворке — переименовать нельзя.
Минимальный templates/404.html:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Страница не найдена</title>
</head>
<body>
<h1>404 — такой страницы нет</h1>
<p>Возможно, ссылка устарела или вы ошиблись адресом.</p>
<p><a href="/">Вернуться на главную</a></p>
</body>
</html>И templates/500.html:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<title>Ошибка сервера</title>
</head>
<body>
<h1>500 — что-то сломалось</h1>
<p>Мы уже знаем о проблеме и разбираемся. Попробуйте зайти позже.</p>
<p><a href="/">На главную</a></p>
</body>
</html>Шаблон 500.html рендерится в аварийном режиме: половины привычного контекста в нём нет. Если что-то ломается — падать уже некуда.
Важное ограничение шаблона 500
В 500.html недоступны контекст-процессоры и переменная request. Django отдаёт этот шаблон, когда произошла необработанная ошибка, и не гарантирует, что окружение цело. Поэтому не тяните в 500.html данные пользователя, меню из базы или что-то, что само может упасть. Держите его статичным: заголовок, текст, ссылка на главную. В 404.html контекст доступен полнее, но и там лучше не завязываться на запросы к БД.
Шаг 3. Отключите DEBUG, чтобы увидеть результат
Пока DEBUG = True, вы будете видеть технические страницы, а не свои. Это не баг — так задумано, чтобы разработчик читал трейсбек. Чтобы проверить кастомные страницы локально, временно поставьте:
# settings.py — только для локальной проверки
DEBUG = False
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]При DEBUG = False список ALLOWED_HOSTS обязателен — иначе Django ответит ошибкой 400 на любой запрос. Перезапустите сервер. Проверка: откройте http://127.0.0.1:8000/no-such-page/ — должна показаться ваша страница 404, а не стандартная.
Как проверить страницу 500
Страницу 500 просто так не увидишь — нужна настоящая необработанная ошибка. Временно добавьте вью, которая падает, и заведите на неё URL:
# views.py
def trigger_error(request):
raise Exception("Тестовая ошибка для проверки 500")
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path("boom/", views.trigger_error),
]Откройте /boom/ при DEBUG = False — увидите свой 500.html. После проверки удалите тестовый URL и вью, чтобы они не уехали в продакшен.
Шаг 4. Верните DEBUG и настройте продакшен правильно
Локально верните DEBUG = True, чтобы снова видеть трейсбеки при разработке. На боевом сервере значение должно приходить из окружения, а не быть зашито в коде:
# settings.py
import os
DEBUG = os.environ.get("DJANGO_DEBUG", "False") == "True"
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "").split(",")Так на проде DEBUG останется False, и пользователи увидят ваши страницы, а не трейсбек с путями к файлам и настройками.
Если нужны страницы 403 и 400
По той же схеме Django подхватывает 403.html (доступ запрещён) и 400.html (неверный запрос). Кладёте файлы с этими именами в корень папки шаблонов — и всё. Отдельно настраивать не нужно.
| Файл | Когда показывается | Есть ли request/контекст |
|---|---|---|
| 404.html | URL не найден | Да, но БД лучше не трогать |
| 500.html | Необработанное исключение | Нет, только статика |
| 403.html | PermissionDenied | Да |
| 400.html | SuspiciousOperation | Да |
Если не получилось
- Всё ещё видна стандартная страница. Скорее всего,
DEBUGосталсяTrue. Кастомные страницы при включённом дебаге не показываются вообще. - Ошибка «Bad Request (400)» на все страницы. Вы поставили
DEBUG = False, но не заполнилиALLOWED_HOSTS. Добавьте туда"127.0.0.1"и"localhost". - TemplateDoesNotExist: 404.html. Файл лежит не там или папка не подключена в
DIRS. Имя должно быть ровно404.htmlв корне папки шаблонов, без подпапок. - Страница 500 сама выдаёт ошибку. В шаблоне
500.htmlвы обращаетесь к переменной, которой в аварийном контексте нет. Уберите всё динамическое, оставьте статичный HTML. - Стили и картинки на странице ошибки не грузятся при DEBUG=False. Django перестаёт раздавать статику сам. На проде статику отдаёт Nginx или whitenoise — это отдельная тема, здесь только шаблоны.
Что делать дальше
Оформите страницы под свой сайт: подключите общий базовый шаблон в 404.html (в 500.html — с осторожностью, помня про урезанный контекст). Настройте раздачу статики на проде, иначе страница ошибки приедет без стилей. И проверьте логирование: при DEBUG = False Django по умолчанию шлёт письма о 500-х ошибках на адреса из ADMINS — настройте это, чтобы узнавать о падениях раньше пользователей.
Тест и проверочная: Быстрые ответы с объяснением, почему остальные варианты неверны
Спросить за 10 ₽Источники: Django docs — Customizing error views, Django docs — DEBUG setting
Частые вопросы
У меня Django 4.2, а не 5.x — всё будет так же?
Почему я вижу стандартную страницу, хотя создал свою?
Можно ли переименовать 404.html во что-то своё?
Почему в 500.html нельзя выводить имя пользователя или меню из базы?
На проде страница ошибки открывается без стилей — это нормально?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.