Install & Compatibility
Where this runs
tested against v6.7.3 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.700s · 76.9MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 3.8s · import 0.624s · 77MB
76MB installed
● package 76MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
RichTextField
✓ from ckeditor.fields import RichTextField
RichTextUploadingField
✓ from ckeditor_uploader.fields import RichTextUploadingField
Use this field if you need image/file upload capabilities.
CKEditorWidget
✓ from ckeditor.widgets import CKEditorWidget
✗ from django_ckeditors.widgets import CKEditorsWidget
The `django_ckeditors` import path is incorrect/outdated for the main `django-ckeditor` library. Always use `ckeditor.widgets` or `ckeditor_uploader.widgets`.
CKEditorUploadingWidget
✓ from ckeditor_uploader.widgets import CKEditorUploadingWidget
✗ from django_ckeditors.widgets import CKEditorsWidget
The `django_ckeditors` import path is incorrect/outdated for the main `django-ckeditor` library. Always use `ckeditor.widgets` or `ckeditor_uploader.widgets`.
This quickstart demonstrates how to integrate `RichTextUploadingField` into a Django model and use the corresponding form and template. It includes the necessary `settings.py` and `urls.py` configurations, emphasizing the crucial `{{ form.media }}` in the template for CKEditor to render correctly. This example assumes a basic Django project structure with a `base.html` template. Remember to run `python manage.py makemigrations` and `python manage.py migrate` after defining the model, and `python manage.py collectstatic` to gather CKEditor's static files. For file uploads, ensure your `MEDIA_ROOT` and `MEDIA_URL` settings are correctly configured.
import os
from django.db import models
from django.forms import ModelForm
from django.shortcuts import render, redirect
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
# --- settings.py additions ---
# INSTALLED_APPS = [
# # ... other apps
# 'ckeditor',
# 'ckeditor_uploader',
# ]
#
# MEDIA_URL = '/media/'
# MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Ensure BASE_DIR is defined
# CKEDITOR_UPLOAD_PATH = 'uploads/'
# CKEDITOR_CONFIGS = {
# 'default': {
# 'toolbar': 'full',
# 'height': 300,
# 'width': '100%',
# 'extraPlugins': 'codesnippet',
# },
# }
#
# # --- urls.py additions (project level) ---
# # from django.urls import include, path
# # from django.conf import settings
# # from django.conf.urls.static import static
# #
# # urlpatterns = [
# # # ... other urls
# # path('ckeditor/', include('ckeditor_uploader.urls')),
# # ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# --- app/models.py ---
from ckeditor_uploader.fields import RichTextUploadingField
class Article(models.Model):
title = models.CharField(max_length=200)
content = RichTextUploadingField(blank=True, null=True)
def __str__(self):
return self.title
# --- app/forms.py ---
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['title', 'content']
# --- app/views.py ---
def create_article(request):
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
form.save()
return redirect('article_list')
else:
form = ArticleForm()
articles = Article.objects.all()
return render(request, 'app/article_form.html', {'form': form, 'articles': articles})
def article_list(request):
articles = Article.objects.all()
return render(request, 'app/article_list.html', {'articles': articles})
# --- app/urls.py (within your app) ---
# urlpatterns = [
# path('create/', create_article, name='create_article'),
# path('', article_list, name='article_list'),
# ]
# --- app/templates/app/article_form.html ---
# {% extends 'base.html' %}
# {% block content %}
# <h2>Create Article</h2>
# <form method="post">
# {% csrf_token %}
# {{ form.media }} {# IMPORTANT: Renders CSS/JS for CKEditor #}
# {{ form.as_p }}
# <button type="submit">Save</button>
# </form>
# <hr/>
# <h2>Articles</h2>
# <ul>
# {% for article in articles %}
# <li>{{ article.title }}</li>
# {% endfor %}
# </ul>
# {% endblock %}
# --- app/templates/app/article_list.html ---
# {% extends 'base.html' %}
# {% block content %}
# <h2>Articles</h2>
# <ul>
# {% for article in articles %}
# <li><a href="#">{{ article.title }}</a></li>
# <div>{{ article.content|safe }}</div> {# Use |safe to render HTML #}
# {% empty %}
# <li>No articles yet. <a href="{% url 'create_article' %}">Create one</a>.</li>
# {% endfor %}
# </ul>
# {% endblock %}
Debug
Known issues
breakingVersion 6.4.0 dropped support for Python versions older than 3.8 and Django versions older than 3.2. Ensure your project meets these minimum requirements before upgrading.fixUpgrade Python to 3.8+ and Django to 3.2+. Review your codebase for deprecated Django features or Python syntax if upgrading from very old versions.
affects: <6.4.0
breakingIn version 6.0.0, the `ugettext_lazy()` function was replaced with `gettext_lazy()`. If you have custom translations or widget templates that directly use `ugettext_lazy()`, they will break.fixReplace all instances of `ugettext_lazy` with `gettext_lazy` in your custom code.
affects: <6.0.0
deprecateddjango-ckeditor bundles CKEditor 4.22.1, which is no longer officially supported by CKSource and has known unfixed security issues. Users are strongly advised to consider switching to CKEditor 5 (using `django-ckeditor-5`) or the non-free CKEditor 4 LTS package for security and continued support.fixEvaluate migrating to `django-ckeditor-5` (a separate project that integrates CKEditor 5) or acquire a license for CKEditor 4 LTS. If migrating, be aware that `django-ckeditor-5` has different import paths and configurations.
affects: All versions bundling CKEditor 4 (currently 6.7.3)
gotchaWhen using `RichTextUploadingField` or `CKEditorUploadingWidget`, you must include `'ckeditor_uploader'` in `INSTALLED_APPS` and add `path('ckeditor/', include('ckeditor_uploader.urls'))` to your project's `urls.py`. Failing to do so will result in broken image/file upload functionality and a 404 error when accessing upload URLs.fixEnsure both `ckeditor_uploader` is in `INSTALLED_APPS` and its URLs are included in your project's `urls.py`.
affects: All versions
gotchaCustomizing the CKEditor widget template (e.g., `ckeditor/widget.html`) might require adjustments with version 6.4.0 and later due to changes in the widget's context, deviating less from standard Django widget contexts.fixReview your custom `ckeditor/widget.html` template and adapt it to the updated context variables. The official documentation or changelog should provide details on the context changes.
affects: >=6.4.0
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'ckeditor' or ModuleNotFoundError: No module named 'ckeditor_uploader'
The 'ckeditor' or 'ckeditor_uploader' application is not properly installed, not added to INSTALLED_APPS, or the Python environment cannot locate the module.
fixEnsure `django-ckeditor` is installed (`pip install django-ckeditor`) and both `'ckeditor'` and `'ckeditor_uploader'` are included in your `INSTALLED_APPS` list in `settings.py`.
NoReverseMatch at /path/to/admin/ Reverse for 'ckeditor_uploader:upload' not found or NoReverseMatch 'ckeditor_uploader:upload' is not a registered namespace
The URL patterns for the `ckeditor_uploader` app, which handles file uploads, are not correctly included in your project's main `urls.py` file.
fixAdd `path('ckeditor/', include('ckeditor_uploader.urls'))` to your project's root `urls.py`. AttributeError: module 'django.db.models' has no attribute 'RichTextUploadingField' or Import 'ckeditor.fields' could not be resolved
The `RichTextUploadingField` (or `RichTextField`) is being imported from the incorrect module; these fields are not directly part of `django.db.models`.
fixImport `RichTextUploadingField` from `ckeditor_uploader.fields` (`from ckeditor_uploader.fields import RichTextUploadingField`). For `RichTextField`, import from `ckeditor.fields` (`from ckeditor.fields import RichTextField`).
CKEditor not showing in admin (plain textarea instead of rich text editor) or CKEditor widget not loading
This typically occurs due to static files not being collected or served correctly, an incorrect `CKEDITOR_BASEPATH` configuration, or missing `{{ form.media }}` in custom templates.
fix1. Ensure `'ckeditor'` is in `INSTALLED_APPS` and run `python manage.py collectstatic`. 2. Verify `STATIC_URL`, `STATIC_ROOT`, `MEDIA_URL`, and `MEDIA_ROOT` are correctly configured in `settings.py`. 3. If rendering forms outside the Django admin, ensure `{{ form.media }}` is included in your template. 4. Optionally, explicitly set `CKEDITOR_BASEPATH = STATIC_URL + 'ckeditor/ckeditor/'` in `settings.py`. Uncaught ReferenceError: CKEDITOR is not defined
CKEditor's static JavaScript files are not being served correctly by Django, preventing the editor from loading and initializing.
fixEnsure 'ckeditor' is in `INSTALLED_APPS`, `STATIC_URL` is configured, and run `python manage.py collectstatic` to gather static files.
Upgrade
Version history
6.7.3latest on PyPI · released Jun 6, 2025
Audit
Dependencies
DjangorequiredCore framework integration.
PillowoptionalRequired for image processing during file uploads. It is now optional as of older changes where image processing was extracted to backends, but practically essential for `RichTextUploadingField` functionality.
django-js-assetrequiredRequired for Django >= 4.1 compatibility, specifically for handling JS assets within widgets.