{"id":5184,"library":"django-ckeditor","title":"Django CKEditor","description":"django-ckeditor integrates the CKEditor 4 WYSIWYG rich text editor into Django projects, providing `RichTextField`, `RichTextUploadingField`, `CKEditorWidget`, and `CKEditorUploadingWidget` for seamless content management in both the admin interface and custom forms. The library is currently at version 6.7.3 and follows Django's release cycle for compatibility updates, though it has an important deprecation warning regarding its bundled CKEditor 4 version.","status":"active","version":"6.7.3","language":"en","source_language":"en","source_url":"https://github.com/django-ckeditor/django-ckeditor","tags":["django","ckeditor","wysiwyg","rich-text-editor","admin","forms","content-management"],"install":[{"cmd":"pip install django-ckeditor","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core framework integration.","package":"Django","optional":false},{"reason":"Required 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.","package":"Pillow","optional":true},{"reason":"Required for Django >= 4.1 compatibility, specifically for handling JS assets within widgets.","package":"django-js-asset","optional":false}],"imports":[{"symbol":"RichTextField","correct":"from ckeditor.fields import RichTextField"},{"note":"Use this field if you need image/file upload capabilities.","symbol":"RichTextUploadingField","correct":"from ckeditor_uploader.fields import RichTextUploadingField"},{"note":"The `django_ckeditors` import path is incorrect/outdated for the main `django-ckeditor` library. Always use `ckeditor.widgets` or `ckeditor_uploader.widgets`.","wrong":"from django_ckeditors.widgets import CKEditorsWidget","symbol":"CKEditorWidget","correct":"from ckeditor.widgets import CKEditorWidget"},{"note":"The `django_ckeditors` import path is incorrect/outdated for the main `django-ckeditor` library. Always use `ckeditor.widgets` or `ckeditor_uploader.widgets`.","wrong":"from django_ckeditors.widgets import CKEditorsWidget","symbol":"CKEditorUploadingWidget","correct":"from ckeditor_uploader.widgets import CKEditorUploadingWidget"}],"quickstart":{"code":"import os\nfrom django.db import models\nfrom django.forms import ModelForm\nfrom django.shortcuts import render, redirect\nfrom django.urls import path, include\nfrom django.conf import settings\nfrom django.conf.urls.static import static\n\n# --- settings.py additions ---\n# INSTALLED_APPS = [\n#     # ... other apps\n#     'ckeditor',\n#     'ckeditor_uploader',\n# ]\n#\n# MEDIA_URL = '/media/'\n# MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # Ensure BASE_DIR is defined\n# CKEDITOR_UPLOAD_PATH = 'uploads/'\n# CKEDITOR_CONFIGS = {\n#     'default': {\n#         'toolbar': 'full',\n#         'height': 300,\n#         'width': '100%',\n#         'extraPlugins': 'codesnippet',\n#     },\n# }\n#\n# # --- urls.py additions (project level) ---\n# # from django.urls import include, path\n# # from django.conf import settings\n# # from django.conf.urls.static import static\n# #\n# # urlpatterns = [\n# #     # ... other urls\n# #     path('ckeditor/', include('ckeditor_uploader.urls')),\n# # ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)\n\n\n# --- app/models.py ---\nfrom ckeditor_uploader.fields import RichTextUploadingField\n\nclass Article(models.Model):\n    title = models.CharField(max_length=200)\n    content = RichTextUploadingField(blank=True, null=True)\n\n    def __str__(self):\n        return self.title\n\n# --- app/forms.py ---\nclass ArticleForm(ModelForm):\n    class Meta:\n        model = Article\n        fields = ['title', 'content']\n\n# --- app/views.py ---\ndef create_article(request):\n    if request.method == 'POST':\n        form = ArticleForm(request.POST)\n        if form.is_valid():\n            form.save()\n            return redirect('article_list')\n    else:\n        form = ArticleForm()\n    articles = Article.objects.all()\n    return render(request, 'app/article_form.html', {'form': form, 'articles': articles})\n\ndef article_list(request):\n    articles = Article.objects.all()\n    return render(request, 'app/article_list.html', {'articles': articles})\n\n# --- app/urls.py (within your app) ---\n# urlpatterns = [\n#     path('create/', create_article, name='create_article'),\n#     path('', article_list, name='article_list'),\n# ]\n\n# --- app/templates/app/article_form.html ---\n# {% extends 'base.html' %}\n# {% block content %}\n#     <h2>Create Article</h2>\n#     <form method=\"post\">\n#         {% csrf_token %}\n#         {{ form.media }} {# IMPORTANT: Renders CSS/JS for CKEditor #}\n#         {{ form.as_p }}\n#         <button type=\"submit\">Save</button>\n#     </form>\n#     <hr/>\n#     <h2>Articles</h2>\n#     <ul>\n#         {% for article in articles %}\n#             <li>{{ article.title }}</li>\n#         {% endfor %}\n#     </ul>\n# {% endblock %}\n\n# --- app/templates/app/article_list.html ---\n# {% extends 'base.html' %}\n# {% block content %}\n#     <h2>Articles</h2>\n#     <ul>\n#         {% for article in articles %}\n#             <li><a href=\"#\">{{ article.title }}</a></li>\n#             <div>{{ article.content|safe }}</div> {# Use |safe to render HTML #}\n#         {% empty %}\n#             <li>No articles yet. <a href=\"{% url 'create_article' %}\">Create one</a>.</li>\n#         {% endfor %}\n#     </ul>\n# {% endblock %}","lang":"python","description":"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."},"warnings":[{"fix":"Upgrade 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.","message":"Version 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.","severity":"breaking","affected_versions":"<6.4.0"},{"fix":"Replace all instances of `ugettext_lazy` with `gettext_lazy` in your custom code.","message":"In 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.","severity":"breaking","affected_versions":"<6.0.0"},{"fix":"Evaluate 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.","message":"django-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.","severity":"deprecated","affected_versions":"All versions bundling CKEditor 4 (currently 6.7.3)"},{"fix":"Ensure both `ckeditor_uploader` is in `INSTALLED_APPS` and its URLs are included in your project's `urls.py`.","message":"When 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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Review 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.","message":"Customizing 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.","severity":"gotcha","affected_versions":">=6.4.0"}],"env_vars":null,"last_verified":"2026-04-13T00:00:00.000Z","next_check":"2026-07-12T00:00:00.000Z"}