Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/django-ckeditor/django-ckeditor
Django admin CKEditor integration.
https://github.com/django-ckeditor/django-ckeditor
Last synced: 5 days ago
JSON representation
Django admin CKEditor integration.
- Host: GitHub
- URL: https://github.com/django-ckeditor/django-ckeditor
- Owner: django-ckeditor
- License: bsd-3-clause
- Created: 2010-03-08T19:20:59.000Z (almost 15 years ago)
- Default Branch: main
- Last Pushed: 2024-12-05T09:37:00.000Z (16 days ago)
- Last Synced: 2024-12-16T13:12:16.880Z (5 days ago)
- Language: JavaScript
- Homepage:
- Size: 13.1 MB
- Stars: 2,417
- Watchers: 53
- Forks: 695
- Open Issues: 8
-
Metadata Files:
- Readme: README.rst
- Changelog: CHANGELOG.rst
- License: LICENSE
- Authors: AUTHORS.rst
Awesome Lists containing this project
- best-of-web-python - GitHub - 3% open · ⏱️ 26.03.2024): (Django Utilities)
- stars - django-ckeditor/django-ckeditor - Django admin CKEditor integration. (JavaScript)
- stars - django-ckeditor/django-ckeditor - Django admin CKEditor integration. (JavaScript)
README
Deprecation notice
==================I do not recommend using this package anymore since the open source version of CKEditor 4 has unfixed security issues. More on this in `my blog post `__. Alternatives are listed `here on Django Packages `__. I personally am using `django-prose-editor `__. Thanks!
Django CKEditor
===============.. image:: https://img.shields.io/pypi/v/django-ckeditor.svg
:target: https://pypi.python.org/pypi/django-ckeditor.. image:: https://img.shields.io/pypi/pyversions/django-ckeditor.svg
:target: https://pypi.org/project/django-ckeditor/.. image:: https://img.shields.io/pypi/djversions/django-ckeditor.svg
:target: https://pypi.org/project/django-ckeditor/.. image:: https://github.com/django-ckeditor/django-ckeditor/workflows/Tests/badge.svg
:target: https://github.com/django-ckeditor/django-ckeditor/actions.. image:: https://readthedocs.org/projects/django-ckeditor/badge/?version=latest&style=flat
:target: https://django-ckeditor.readthedocs.io/en/latest/**Django admin CKEditor integration.**
Provides a ``RichTextField``, ``RichTextUploadingField``, ``CKEditorWidget`` and ``CKEditorUploadingWidget`` utilizing CKEditor with image uploading and browsing support included.
This version also includes:
#. support to django-storages (works with S3)
#. updated ckeditor to version 4.18.0
#. included all ckeditor language and plugin files to make everyone happy! ( `only the plugins maintained by the ckeditor develops team `__ ).. contents:: Contents
:depth: 5Installation
------------Required
~~~~~~~~
#. Install or add django-ckeditor to your python path.
::pip install django-ckeditor
#. Add ``ckeditor`` to your ``INSTALLED_APPS`` setting.
#. Run the ``collectstatic`` management command: ``$ ./manage.py collectstatic``. This will copy static CKEditor required media resources into the directory given by the ``STATIC_ROOT`` setting. See `Django's documentation on managing static files `__ for more info.
#. CKEditor needs to know where its assets are located because it loads them
lazily only when needed. The location is determined in the ``ckeditor-init.js``
script. and defaults to ``static/ckeditor/ckeditor/``. This does not work all
the time, for example when using ``ManifestStaticFilesStorage``, any asset
packaging pipeline or whatnot. django-ckeditor is quite good at automatically
detecting the correct place even then, but sometimes you have to hardcode
``CKEDITOR_BASEPATH`` somewhere. This can be hardcoded in settings, i.e.::CKEDITOR_BASEPATH = "/my_static/ckeditor/ckeditor/"
It is possible to override
the ``admin/change_form.html`` template with your own if you really need to do
this, i.e.::{% extends "admin/change_form.html" %}
{% block extrahead %}
window.CKEDITOR_BASEPATH = '/my_static/ckeditor/ckeditor/';
{{ block.super }}
{% endblock %}Of course, you should adapt this snippet to your needs when using
CKEditor outside the admin app.Required for using widget with file upload
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#. Add ``ckeditor_uploader`` to your ``INSTALLED_APPS`` setting.
#. Add a ``CKEDITOR_UPLOAD_PATH`` setting to the project's ``settings.py`` file. This setting specifies a relative path to your CKEditor media upload directory. CKEditor uses Django's storage API. By default, Django uses the file system storage backend (it will use your ``MEDIA_ROOT`` and ``MEDIA_URL``) and if you don't use a different backend you have to have write permissions for the ``CKEDITOR_UPLOAD_PATH`` path within ``MEDIA_ROOT``, i.e.::
CKEDITOR_UPLOAD_PATH = "uploads/"
When using default file system storage, images will be uploaded to "uploads" folder in your ``MEDIA_ROOT`` and urls will be created against ``MEDIA_URL`` (``/media/uploads/image.jpg``).
If you want to be able to have control over filename generation, you have to add a custom filename generator to your settings::
# utils.py
def get_filename(filename, request):
return filename.upper()::
# settings.py
CKEDITOR_FILENAME_GENERATOR = 'utils.get_filename'
CKEditor has been tested with django FileSystemStorage and S3BotoStorage.
There are issues using S3Storage from django-storages.#. For the default filesystem storage configuration, ``MEDIA_ROOT`` and ``MEDIA_URL`` must be set correctly for the media files to work (like those uploaded by the ckeditor widget).
#. Add CKEditor URL include to your project's ``urls.py`` file::
path('ckeditor/', include('ckeditor_uploader.urls')),
#. Note that by adding those URLs you add views that can upload and browse through uploaded images. Since django-ckeditor 4.4.6, those views are decorated using ``@staff_member_required``. If you want a different permission decorator (``login_required``, ``user_passes_test`` etc.) then add views defined in ``ckeditor.urls`` manually to your urls.py.
Optional - customizing CKEditor editor
--------------------------------------#. Add a CKEDITOR_CONFIGS setting to the project's ``settings.py`` file. This specifies sets of CKEditor settings that are passed to CKEditor (see CKEditor's `Setting Configurations `__), i.e.::
CKEDITOR_CONFIGS = {
'awesome_ckeditor': {
'toolbar': 'Basic',
},
}The name of the settings can be referenced when instantiating a RichTextField::
content = RichTextField(config_name='awesome_ckeditor')
The name of the settings can be referenced when instantiating a CKEditorWidget::
widget = CKEditorWidget(config_name='awesome_ckeditor')
By specifying a set named ``default`` you'll be applying its settings to all RichTextField and CKEditorWidget objects for which ``config_name`` has not been explicitly defined ::
CKEDITOR_CONFIGS = {
'default': {
'toolbar': 'full',
'height': 300,
'width': 300,
},
}It is possible to create a custom toolbar ::
CKEDITOR_CONFIGS = {
'default': {
'toolbar': 'Custom',
'toolbar_Custom': [
['Bold', 'Italic', 'Underline'],
['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
['Link', 'Unlink'],
['RemoveFormat', 'Source']
]
}
}If you want or need plugins which are not part of django-ckeditor's
plugin set you may specify assets and plugins as follows::text = RichTextField(
config_name='forum-post',# CKEDITOR.config.extraPlugins:
extra_plugins=['someplugin'],# CKEDITOR.plugins.addExternal(...)
external_plugin_resources=[(
'someplugin',
'/static/.../path-to-someplugin/',
'plugin.js',
)],
)Alternatively, those settings can also be provided through
``CKEDITOR_CONFIGS``.Optional for file upload
~~~~~~~~~~~~~~~~~~~~~~~~
#. All uploaded files are slugified by default. To disable this feature, set ``CKEDITOR_UPLOAD_SLUGIFY_FILENAME`` to ``False``.#. Set the ``CKEDITOR_RESTRICT_BY_USER`` setting to ``True`` in the project's ``settings.py`` file (default ``False``). This restricts access to uploaded images to the uploading user (e.g. each user only sees and uploads their own images). Upload paths are prefixed by the string returned by ``get_username``. If ``CKEDITOR_RESTRICT_BY_USER`` is set to a string, the named property is used instead. Superusers can still see all images. **NOTE**: This restriction is only enforced within the CKEditor media browser.
#. Set the ``CKEDITOR_BROWSE_SHOW_DIRS`` setting to ``True`` to show directories on the "Browse Server" page. This enables image grouping by directory they are stored in, sorted by date.
#. Set the ``CKEDITOR_RESTRICT_BY_DATE`` setting to ``True`` to bucked uploaded files by year/month/day.
#. You can set a custom file storage for CKEditor uploader by defining it under ``CKEDITOR_STORAGE_BACKEND`` variable in settings.
#. You can set ``CKEDITOR_IMAGE_BACKEND`` to one of the supported backends to enable thumbnails in ckeditor gallery.
By default, no thumbnails are created and full-size images are used as preview.
Supported backends:- ``ckeditor_uploader.backends.PillowBackend``: Uses Pillow
#. With the ``PillowBackend`` backend, you can change the thumbnail size with the ``CKEDITOR_THUMBNAIL_SIZE`` setting (formerly ``THUMBNAIL_SIZE``).
Default value: (75, 75)#. With the ``PillowBackend`` backend, you can convert and compress the uploaded images to jpeg, to save disk space.
Set the ``CKEDITOR_FORCE_JPEG_COMPRESSION`` setting to ``True`` (default ``False``)
You can change the ``CKEDITOR_IMAGE_QUALITY`` setting (formerly ``IMAGE_QUALITY``), which is passed to Pillow:The image quality, on a scale from 1 (worst) to 95 (best). The default is 75. Values above 95
should be avoided; 100 disables portions of the JPEG compression algorithm and results in
large files with hardly any gain in image quality.This feature is disabled for animated images.
Usage
-----Field
~~~~~
The quickest way to add rich text editing capabilities to your models is to use the included ``RichTextField`` model field type. A CKEditor widget is rendered as the form field but in all other regards the field behaves like the standard Django ``TextField``. For example::from django.db import models
from ckeditor.fields import RichTextFieldclass Post(models.Model):
content = RichTextField()**For file upload support** use ``RichTextUploadingField`` from ``ckeditor_uploader.fields``.
Widget
~~~~~~
Alternatively, you can use the included ``CKEditorWidget`` as the widget for a formfield. For example::from django import forms
from django.contrib import admin
from ckeditor.widgets import CKEditorWidgetfrom post.models import Post
class PostAdminForm(forms.ModelForm):
content = forms.CharField(widget=CKEditorWidget())
class Meta:
model = Post
fields = '__all__'class PostAdmin(admin.ModelAdmin):
form = PostAdminFormadmin.site.register(Post, PostAdmin)
**For file upload support** use ``CKEditorUploadingWidget`` from ``ckeditor_uploader.widgets``.
**Overriding widget template**
In Django >=1.11 for overriding ``ckeditor/widget.html`` you have three ways:
#. Place ``ckeditor/widget.html`` in ``BASE_DIR/templates``
- Change ``FORM_RENDERER`` to ``TemplateSettings``.
::
FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
- Include ``templates`` folder in ``DIRS``
::
TEMPLATES = [{
...
'DIRS': [os.path.join(BASE_DIR, 'templates'), ],
...
}]- Add ``'django.forms'`` to ``INSTALLED_APPS``.
#. Place ``ckeditor/widget.html`` in ``your_app/templates`` and place ``'your_app'`` **before** ``'ckeditor'`` and ``'ckeditor_uploader'`` in ``INSTALLED_APPS``.
#. Inherit from ``CKEditorWidget`` and override ``template_name`` with a custom template available in TEMPLATES DIRS as defined settings.py.
::
class MyCustomCKEditorWidget(CKEditorWidget):
template_name = "templates/custom_ckeditor/widget.html"Outside of django admin
~~~~~~~~~~~~~~~~~~~~~~~When you are rendering a form outside the admin panel, you'll have to make sure all form media is present for the editor to work. One way to achieve this is like this::
{{ myform.media }}
{{ myform.as_p }}
or you can load the media manually as it is done in the demo app::
{% load static %}
When you need to render ``RichTextField``'s HTML output in your templates safely, just use ``{{ content|safe }}``, `Django's safe filter `_
Management Commands
~~~~~~~~~~~~~~~~~~~
Included is a management command to create thumbnails for images already contained in ``CKEDITOR_UPLOAD_PATH``. This is useful to create thumbnails when using django-ckeditor with existing images. Issue the command as follows::$ ./manage.py generateckeditorthumbnails
**NOTE**: If you're using custom views remember to include ckeditor.js in your form's media either through ``{{ form.media }}`` or through a ```` tag. Admin will do this for you automatically. See `Django's Form Media docs <http://docs.djangoproject.com/en/dev/topics/forms/media/>`__ for more info.
Using S3
~~~~~~~~
See https://django-storages.readthedocs.org/en/latest/**NOTE:** ``django-ckeditor`` will not work with S3 through ``django-storages`` without this line in ``settings.py``::
AWS_QUERYSTRING_AUTH = False
If you want to use allowedContent
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To get allowedContent to work, disable **stylesheetparser** plugin.
So include this in your settings.py.::CKEDITOR_CONFIGS = {
"default": {
"removePlugins": "stylesheetparser",
}
}Plugins:
--------django-ckeditor includes the following ckeditor plugins, but not all are enabled by default::
a11yhelp, about, adobeair, ajax, autoembed, autogrow, autolink, bbcode, clipboard, codesnippet,
codesnippetgeshi, colordialog, devtools, dialog, div, divarea, docprops, embed, embedbase,
embedsemantic, filetools, find, flash, forms, iframe, iframedialog, image, image2, language,
lineutils, link, liststyle, magicline, mathjax, menubutton, notification, notificationaggregator,
pagebreak, pastefromword, placeholder, preview, scayt, sharedspace, showblocks, smiley,
sourcedialog, specialchar, stylesheetparser, table, tableresize, tabletools, templates, uicolor,
uploadimage, uploadwidget, widget, wsc, xmlThe image/file upload feature is done by the `uploadimage` plugin.
Restricting file upload
-----------------------#. To restrict upload functionality to image files only, add ``CKEDITOR_ALLOW_NONIMAGE_FILES = False`` in your settings.py file. Currently non-image files are allowed by default.
#. By default the upload and browse URLs use staff_member_required decorator - ckeditor_uploader/urls.py - if you want other decorators just insert two urls found in that urls.py and don't include it.
Demo / Test application
-----------------------If you clone the repository you will be able to run the ``ckeditor_demo`` application.
#. ``pip install -r ckeditor_demo_requirements.txt``
#. Run ``python manage.py migrate``
#. Create a superuser if you want to test the widget in the admin panel
#. Start the development server.
There is a forms.Form on the main page (/) and a model in admin that uses the widget for a model field.
Database is set to sqlite3 and STATIC/MEDIA_ROOT to folders in temporary directory.Running selenium test
---------------------The recommended way to run selenium tests is using tox. Select the appropriate
selenium driver using the ``SELENIUM`` environment variable and optionally
specify that you want to run only one environment since selenium takes some
time and/or since you do not have all supported versions of Python installed
locally. The example uses the combination of Python 3.9 and Django 4.0 which is
a supported combination at the time of writing::# Either
SELENIUM=firefox tox -e py39-dj40# Or
SELENIUM=chromium tox -e py39-dj40# Or even
SELENIUM=firefox toxTroubleshooting
---------------If your browser has problems displaying uploaded images in the image upload window you may need to change Django settings:
::
X_FRAME_OPTIONS = 'SAMEORIGIN'
More on https://docs.djangoproject.com/en/1.11/ref/clickjacking/#setting-x-frame-options-for-all-responses
Example ckeditor configuration
------------------------------::
CKEDITOR_CONFIGS = {
'default': {
'skin': 'moono',
# 'skin': 'office2013',
'toolbar_Basic': [
['Source', '-', 'Bold', 'Italic']
],
'toolbar_YourCustomToolbarConfig': [
{'name': 'document', 'items': ['Source', '-', 'Save', 'NewPage', 'Preview', 'Print', '-', 'Templates']},
{'name': 'clipboard', 'items': ['Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo']},
{'name': 'editing', 'items': ['Find', 'Replace', '-', 'SelectAll']},
{'name': 'forms',
'items': ['Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton',
'HiddenField']},
'/',
{'name': 'basicstyles',
'items': ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat']},
{'name': 'paragraph',
'items': ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote', 'CreateDiv', '-',
'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl',
'Language']},
{'name': 'links', 'items': ['Link', 'Unlink', 'Anchor']},
{'name': 'insert',
'items': ['Image', 'Flash', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar', 'PageBreak', 'Iframe']},
'/',
{'name': 'styles', 'items': ['Styles', 'Format', 'Font', 'FontSize']},
{'name': 'colors', 'items': ['TextColor', 'BGColor']},
{'name': 'tools', 'items': ['Maximize', 'ShowBlocks']},
{'name': 'about', 'items': ['About']},
'/', # put this to force next toolbar on new line
{'name': 'yourcustomtools', 'items': [
# put the name of your editor.ui.addButton here
'Preview',
'Maximize',]},
],
'toolbar': 'YourCustomToolbarConfig', # put selected toolbar config here
# 'toolbarGroups': [{ 'name': 'document', 'groups': [ 'mode', 'document', 'doctools' ] }],
# 'height': 291,
# 'width': '100%',
# 'filebrowserWindowHeight': 725,
# 'filebrowserWindowWidth': 940,
# 'toolbarCanCollapse': True,
# 'mathJaxLib': '//cdn.mathjax.org/mathjax/2.2-latest/MathJax.js?config=TeX-AMS_HTML',
'tabSpaces': 4,
'extraPlugins': ','.join([
'uploadimage', # the upload image feature
# your extra plugins here
'div',
'autolink',
'autoembed',
'embedsemantic',
'autogrow',
# 'devtools',
'widget',
'lineutils',
'clipboard',
'dialog',
'dialogui',
'elementspath'
]),
}
}