Bootstrap в Django без боли: пошаговая настройка
За 20–30 минут вы подключите Bootstrap 5 к Django-проекту, соберёте статику через collectstatic и настроите базовый шаблон, от которого будут наследоваться остальные страницы.

К концу этого руководства у вас будет Django-проект с рабочим Bootstrap 5: навигационное меню, сетка и кнопки отрисуются с фирменными стилями, а статика будет отдаваться правильно и в разработке, и при подготовке к продакшену. На всё уйдёт 20–30 минут, если Python и Django уже установлены. Разберём два способа подключения — через CDN и через локальные файлы — и объясним, когда какой выбирать.
Что нужно иметь до начала
Проверьте, что у вас есть, прежде чем что-то делать. На пятом шаге не хочется узнать, что не хватает базовой установки.
- Python 3.10 или новее (
python --version). - Django 5.x, установленный в виртуальном окружении (
python -m django --version). Если версия другая — большинство шагов совпадёт, но пути настроек статики стабильны начиная с Django 3.x. - Уже созданный проект: есть каталог с
manage.pyи хотя бы одно приложение. - Версия Bootstrap, о которой идёт речь, — 5.3.x. У пятой ветки нет зависимости от jQuery, это важно для примеров ниже.
Если проекта ещё нет, создайте минимальный: django-admin startproject mysite, затем внутри python manage.py startapp pages. Приложение pages добавьте в INSTALLED_APPS.
Способ 1. Bootstrap через CDN — быстрый старт
Самый короткий путь. Ничего не скачиваете, файлы тянутся с внешнего сервера. Подходит для прототипа, учебного проекта или сайта, где допустима зависимость от внешнего CDN.
-
Создайте каталог для шаблонов и базовый шаблон. В корне проекта:
templates/base.html.<!doctype html> <html lang="ru"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %}Мой сайт{% endblock %}</title> <!-- Bootstrap 5.3 CSS с CDN --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> {% block content %}{% endblock %} <!-- JS-бандл с Popper для выпадающих меню и модалок --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script> </body> </html> -
Укажите Django, где искать
templates. Вsettings.pyв спискеTEMPLATESв ключеDIRS:# settings.py 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, # ... остальное без изменений }, ] -
Создайте страницу, которая наследует базовый шаблон:
templates/home.html.{% extends "base.html" %} {% block title %}Главная{% endblock %} {% block content %} <nav class="navbar navbar-expand-lg bg-body-tertiary"> <div class="container"> <a class="navbar-brand" href="#">MySite</a> </div> </nav> <div class="container mt-4"> <h1 class="display-5">Bootstrap подключён</h1> <button class="btn btn-primary">Синяя кнопка</button> </div> {% endblock %} -
Свяжите view и URL. В
urls.pyпроекта:from django.contrib import admin from django.urls import path from django.views.generic import TemplateView urlpatterns = [ path("admin/", admin.site.urls), path("", TemplateView.as_view(template_name="home.html")), ]
Проверка: запустите python manage.py runserver и откройте http://127.0.0.1:8000/. Кнопка должна быть синей и скруглённой, заголовок — крупным. Если кнопка серая и без стилей — CSS не подтянулся, смотрите раздел про ошибки.
Способ 2. Локальные файлы через collectstatic
CDN хорош для старта, но он даёт внешнюю зависимость: если jsdelivr недоступен, сайт остаётся без стилей. Для продакшена лучше держать Bootstrap у себя. Здесь вступает в игру система статики Django.
Статика в Django живёт в двух режимах. В разработке файлы отдаются прямо из папок приложений. В продакшене их собирают одной командой в единый каталог, который раздаёт веб-сервер. Путаница между этими режимами — источник большинства «почему стили не грузятся».
-
Скачайте скомпилированный Bootstrap с официального сайта getbootstrap.com (раздел Download, ветка 5.3.x). Внутри архива нужны
bootstrap.min.cssиbootstrap.bundle.min.js. -
Положите их в каталог статики. Создайте в корне проекта структуру и разложите файлы:
static/ css/ bootstrap.min.css js/ bootstrap.bundle.min.js -
Настройте пути статики в
settings.py. Здесь важны три параметра:# settings.py STATIC_URL = "/static/" # откуда collectstatic берёт файлы в разработке STATICFILES_DIRS = [BASE_DIR / "static"] # куда collectstatic складывает всё для продакшена STATIC_ROOT = BASE_DIR / "staticfiles"Разница между этими двумя каталогами — ключевая, вынесем её в таблицу ниже.
-
Подключите файлы в
base.htmlчерез тег{% static %}вместо ссылок на CDN:{% load static %} <!doctype html> <html lang="ru"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>{% block title %}Мой сайт{% endblock %}</title> <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet"> </head> <body> {% block content %}{% endblock %} <script src="{% static 'js/bootstrap.bundle.min.js' %}"></script> </body> </html>Тег
{% load static %}должен стоять в начале файла, до первого использования{% static %}. -
Проверьте, что в
INSTALLED_APPSестьdjango.contrib.staticfiles— по умолчанию он там. Именно он даёт тег{% static %}и командуcollectstatic.
Проверка в разработке: с DEBUG = True запустите runserver — файлы отдаются автоматически из STATICFILES_DIRS, никаких дополнительных команд не нужно. Откройте страницу: стили на месте.
Проверка перед продакшеном: выполните python manage.py collectstatic. В консоли появится строка вида «X static files copied to '.../staticfiles'». После этого каталог staticfiles раздаёт Nginx или другой сервер — сам Django с DEBUG = False статику не отдаёт.
STATICFILES_DIRS против STATIC_ROOT
Эти два параметра путают чаще всего. Указать один вместо другого — и collectstatic либо ничего не найдёт, либо перезапишет ваши исходники.
| Параметр | Роль | Кто с ним работает |
|---|---|---|
STATICFILES_DIRS | Список папок с вашими исходными файлами | Откуда collectstatic читает |
STATIC_ROOT | Одна папка, куда всё собирается | Куда collectstatic пишет, откуда раздаёт сервер |
STATIC_URL | Префикс URL для ссылок | Что подставляет тег {% static %} |
STATIC_ROOT и папки из STATICFILES_DIRS не должны совпадать — Django на это ругается при запуске collectstatic.
CDN или локальные файлы: что выбрать
- CDN — прототип, демо, обучение. Ноль настройки, но зависимость от внешнего сервиса и невозможность работать офлайн.
- Локальные файлы — любой проект, который дойдёт до продакшена. Контроль версии, работа без интернета, никакой сторонней аналитики в запросах.
Пакеты вроде django-bootstrap5[1] дают шаблонные теги для форм и заметно упрощают вёрстку Django-форм. Это отдельная тема — здесь мы подключаем чистый Bootstrap руками, чтобы понимать, что происходит под капотом.
Если не получилось
Пять ошибок, которые встречаются почти всегда.
- Страница без стилей, кнопки серые. Откройте вкладку Network в браузере: если запрос к
bootstrap.min.cssотдаёт 404 — путь в{% static %}не совпадает с реальным расположением файла внутриstatic/. Invalid block tag 'static'в шаблоне. Забыли{% load static %}в начале файла. Тег статики не работает без загрузки библиотеки тегов.TemplateDoesNotExist: home.html. Django не видит папкуtemplates. Проверьте, что она указана вTEMPLATES → DIRS, и что путь собран черезBASE_DIR, а не хардкодом.- После
collectstaticсDEBUG = Falseстили пропали. С отключённым дебагом Django не раздаёт статику сам. Это задача веб-сервера. В разработке вернитеDEBUG = Trueили используйте пакет для локальной отдачи собранной статики. - Выпадающее меню и модалки не открываются. Подключили только CSS, забыли JS-бандл. Bootstrap 5 нужен
bootstrap.bundle.min.js(в нём уже есть Popper) перед закрывающим</body>.
Что делать дальше
Базовый шаблон готов, дальше наращивайте. Разбейте base.html на блоки для футера и боковой панели. Если в проекте много форм — посмотрите в сторону django-bootstrap5, он избавит от ручной разметки классов у каждого поля. Перед выкаткой на боевой сервер настройте раздачу каталога STATIC_ROOT через Nginx и один раз прогоните collectstatic в пайплайне деплоя — тогда стили не отвалятся в продакшене.
[1] Тег шаблона (template tag) — конструкция в фигурных скобках с процентами, например {% static %}, которую Django обрабатывает при рендеринге страницы и заменяет на результат: путь, кусок HTML или значение переменной.
Саммаризатор: 50 страниц или созвон — в 5 главных тезисов.
Спросить за 15 ₽Источники: Django — Managing static files (documentation), Bootstrap — Download (getbootstrap.com)
Частые вопросы
У меня Django 4.2, а не 5.x — шаги подойдут?
Обязательно ли скачивать Bootstrap, или можно оставить CDN в продакшене?
Почему после DEBUG = False стили перестали грузиться?
Нужен ли jQuery для Bootstrap в Django?
Что делать, если появляется ошибка Invalid block tag 'static'?
STATICFILES_DIRS и STATIC_ROOT — можно ли указать одну и ту же папку?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.