Как подключить WYSIWYG-редактор в админку Django: гайд
За 20–30 минут вы замените обычное текстовое поле в админке Django на визуальный редактор с форматированием: заголовки, списки, ссылки и жирный текст будут вставляться кнопками, а не руками.

По умолчанию поле TextField в админке Django — это простой многострочный ввод без всякого форматирования. Если в этом поле лежит текст статьи или описание товара, редактору приходится вручную писать HTML или мириться с голым текстом. В конце этой инструкции у вас будет визуальный редактор (WYSIWYG) прямо в форме админки: панель с кнопками для жирного, списков, ссылок и заголовков. На всё уйдёт 20–30 минут.
Разберём один конкретный путь — пакет django-ckeditor с редактором CKEditor 4. Это самый ходовой вариант для Django, он ставится через pip и не требует ручной сборки фронтенда. Инструкция проверена на Django 4.2 и 5.x, Python 3.10+.
Что нужно иметь до начала
- Работающий проект Django (4.2 или 5.x), в который вы уже заходите в админку по адресу
/admin/. - Модель с полем
TextField, которое хотите превратить в редактор. В примере это модельArticleс полемbody. - Доступ к терминалу, где активировано виртуальное окружение проекта.
- Права на редактирование файлов
settings.py,models.py,urls.py.
Загрузка картинок через редактор — отдельная тема, здесь она затронута только в последнем разделе. Сначала поднимаем текстовое форматирование.
Шаг 1. Установите пакет
В активированном окружении выполните:
pip install django-ckeditor
Проверка: команда pip show django-ckeditor должна показать установленную версию (на момент написания — 6.x).
Шаг 2. Подключите приложение в настройках
Откройте settings.py и добавьте ckeditor в список INSTALLED_APPS. Если планируете загрузку файлов через редактор — добавьте и ckeditor_uploader.
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
# добавили редактор
"ckeditor",
"ckeditor_uploader",
# ваши приложения
"blog",
]
Проверка: запустите python manage.py check — ошибок про неизвестное приложение быть не должно.
Шаг 3. Пропишите путь для загрузок и медиа
Этот шаг нужен, только если подключили ckeditor_uploader. В settings.py задайте, куда складывать загруженные файлы и по какому URL их отдавать:
import os
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
# папка внутри MEDIA_ROOT, куда редактор кладёт загруженные файлы
CKEDITOR_UPLOAD_PATH = "uploads/"
Проверка: значения появились в файле, при перезапуске сервера ошибок про отсутствие MEDIA_ROOT нет.
Шаг 4. Замените поле в модели
Откройте models.py вашего приложения. Вместо models.TextField() используйте RichTextField — или RichTextUploadingField, если хотите загрузку картинок прямо из редактора.
from django.db import models
from ckeditor.fields import RichTextField
# для загрузки файлов через редактор — другой импорт:
# from ckeditor_uploader.fields import RichTextUploadingField
class Article(models.Model):
title = models.CharField("Заголовок", max_length=200)
# было: body = models.TextField("Текст")
body = RichTextField("Текст")
def __str__(self):
return self.title
Тип данных в базе не меняется — под капотом это тот же текстовый столбец, поэтому существующие записи не пострадают.
Шаг 5. Создайте и примените миграцию
Хотя тип столбца в базе прежний, Django фиксирует смену класса поля в миграции. Выполните:
python manage.py makemigrations
python manage.py migrate
Проверка: в выводе makemigrations появится строка вроде Alter field body on article, а migrate завершится без ошибок.
Шаг 6. Подключите маршрут загрузчика
Снова — только для варианта с ckeditor_uploader. В корневом urls.py добавьте маршрут и раздачу медиа в режиме разработки:
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path("admin/", admin.site.urls),
path("ckeditor/", include("ckeditor_uploader.urls")),
]
# раздача загруженных файлов при DEBUG=True
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Проверка: сервер запускается без ошибок про несуществующий модуль ckeditor_uploader.urls.
Шаг 7. Соберите статику
Редактор — это JS и CSS, которые должны попасть туда, откуда их отдаёт сервер. Если у вас настроен STATIC_ROOT, выполните:
python manage.py collectstatic
В режиме разработки с DEBUG=True и стандартным runserver статика отдаётся автоматически, но команду всё равно стоит прогнать перед выкладкой на прод.
Проверка: команда сообщит, сколько файлов скопировано, среди путей будут файлы из папки ckeditor.
Шаг 8. Убедитесь, что модель есть в админке
Отдельная настройка админки не нужна — достаточно, чтобы модель была зарегистрирована. В admin.py:
from django.contrib import admin
from .models import Article
admin.site.register(Article)
Запустите сервер:
python manage.py runserver
Проверка: зайдите в /admin/, откройте создание статьи. Вместо серого текстового поля должна появиться панель с кнопками форматирования — жирный, курсив, списки, ссылка. Наберите текст, нажмите жирный, сохраните — при повторном открытии форматирование сохранится.
Тип столбца в базе не изменился: редактор хранит обычный HTML в текстовом поле. Значит, при выводе на сайт этот HTML нужно отрисовывать, а не экранировать — иначе читатель увидит теги как текст.
Как вывести результат на сайте
В шаблоне поле по умолчанию экранируется, и вместо жирного текста вы увидите <strong>. Отключите экранирование фильтром safe:
<div class="article-body">{{ article.body|safe }}</div>
Фильтр safe* говорит шаблонизатору не превращать теги в текст. Применяйте его только к содержимому, которое заполняют доверенные редакторы через админку — не к тому, что вводят анонимные пользователи, иначе открываете дверь для XSS.
* XSS (cross-site scripting) — внедрение чужого JavaScript в вашу страницу через непроверенный ввод. Вывод «сырого» HTML от недоверенного источника — типичный способ его получить.
Если не получилось
- В форме по-прежнему обычное текстовое поле, редактора нет. Чаще всего не загрузилась статика. Откройте консоль браузера (F12): если там 404 на файлы из
/static/ckeditor/, прогонитеcollectstaticи проверьте, чтоSTATIC_URLи раздача статики настроены. - ModuleNotFoundError: No module named 'ckeditor'. Пакет установлен в другое окружение. Убедитесь, что виртуальное окружение активировано, и повторите
pip install django-ckeditor. - При загрузке картинки — 404 или «Page not found» на адрес ckeditor. Не подключён маршрут из шага 6 либо забыт
ckeditor_uploaderвINSTALLED_APPS. Проверьте оба. - Картинка загрузилась, но не показывается. Файл лёг в
MEDIA_ROOT, но сервер его не отдаёт. В разработке проверьте блокstatic(...)вurls.py; на проде раздачуMEDIA_URLнастраивает веб-сервер (Nginx), а не Django. - На странице выводятся теги как текст. Забыт фильтр
|safeв шаблоне.
Что делать дальше
Базовый редактор работает. Дальше стоит настроить панель инструментов под свои нужды — в settings.py задаётся словарь CKEDITOR_CONFIGS, где можно оставить только нужные кнопки и высоту поля. Точные ключи конфигурации сверяйте с документацией django-ckeditor: набор опций зависит от версии.
Отдельно продумайте безопасность: HTML из редактора попадает на сайт как есть, поэтому либо ограничьте доступ к админке доверенными сотрудниками, либо прогоняйте вывод через очистку (например, библиотекой bleach) с белым списком тегов. И держите в голове, что CKEditor 4 — устаревающая ветка; для новых проектов имеет смысл заранее оценить пакеты на базе CKEditor 5 или TinyMCE.
Редактор изображений: Убрать лишнее, заменить фон, добавить объект, расширить кадр — на вашем изображении.
Спросить за 20 ₽Источники: django-ckeditor — документация и репозиторий, Django — Managing static files
Частые вопросы
У меня Django 3.2, инструкция подойдёт?
Нужно ли менять существующие записи в базе после смены поля?
Редактор появился, но кнопки не работают и в консоли 404 — что делать?
Можно обойтись без загрузки картинок и не подключать ckeditor_uploader?
Безопасно ли выводить содержимое редактора через фильтр safe?
Стоит ли ставить CKEditor 4 в 2024 году?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.