Package: django-richtextfield
A Django model field and widget that renders a customizable rich
text/WYSIWYG widget.Works in Django’s admin interface and “normal” forms.Supports globaleditor settings, reusableeditor profilesand perfield & widget settings. There’s built-in support for
pluggable server sidecontent sanitizers.Tested withTinyMCEandCKEditor. Designed to be easily extended to
use other editors.QuickstartInstalldjango-richtextfieldand add it to your Django
project’sINSTALLED_APPS,django.contrib.adminmust also be inINSTALLED_APPS:INSTALLED_APPS = [
    'django.contrib.admin',
    ...
    'djrichtextfield'
]Add the urls to the project’s urlpatterns:path('djrichtextfield/', include('djrichtextfield.urls'))Configuredjango-richtextfieldinsettings.py:DJRICHTEXTFIELD_CONFIG = {
    'js': ['//cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js'],
    'init_template': 'djrichtextfield/init/tinymce.js',
    'settings': {
        'menubar': False,
        'plugins': 'link image',
        'toolbar': 'bold italic | link image | removeformat',
        'width': 700
    }
}Now you’re ready to use the field in your models:from djrichtextfield.models import RichTextField

class Post(models.Model):
    content = RichTextField()or forms:from djrichtextfield.widgets import RichTextWidget

class CommentForm(forms.ModelForm):
    content = forms.CharField(widget=RichTextWidget())When using the editor outside of the admin make sure to includeform.mediain the<head>of the template:<head>
  ...
  {{ form.media }}
  ...
</head>ConfigurationDefine theDJRICHTEXTFIELD_CONFIGdictionary in your project settings.
This dictionary can have the following keys:Javascript souce(s)'js'A list of required javascript files. These can be URLs to a CDN or paths
relative to yourSTATIC_URLe.g.:'js': ['//cdn.ckeditor.com/4.14.0/standard/ckeditor.js']or:'js': ['path/to/editor.js', 'path/to/plugin.js']CSS souce(s)'css'A dictionary of CSS files required.
These can be URLs to a CDN or paths relative to yourSTATIC_URLe.g.:'css': {
    'all': [
        'https://cdn.example.com/css/editor.css'
    ]
}or:'css': {'all': ['path/to/editor.css', 'path/to/plugin.css']}Editor init template'init_template'Path to theinit templatefor your editor. Currentlydjango-richtextfieldships with two templates, either:'init_template': 'djrichtextfield/init/tinymce.js'or:'init_template': 'djrichtextfield/init/ckeditor.js'Editor settings'settings'A Python dictionary with thedefaultconfiguration data for your
editor e.g.:'settings': {  # TinyMCE
    'menubar': False,
    'plugins': 'link image',
    'toolbar': 'bold italic | link image | removeformat',
    'width': 700
}or:'settings': {  # CKEditor
    'toolbar': [
        {'items': ['Format', '-', 'Bold', 'Italic', '-',
                   'RemoveFormat']},
        {'items': ['Link', 'Unlink', 'Image', 'Table']},
        {'items': ['Source']}
    ],
    'format_tags': 'p;h1;h2;h3',
    'width': 700
}Editor profiles'profiles'This is anoptionalconfiguration key. Profiles are “named” custom
settings used to configure specific type of fields. You can configure
profiles like this:'profiles': {
    'basic': {
        'toolbar': 'bold italic | removeformat'
    },
    'advanced': {
        'plugins': 'link image table code',
        'toolbar': 'formatselect | bold italic | removeformat |'
                   ' link unlink image table | code'
    }
}NoteA profile is treated the same way as directly definedfield & widget settings. This means that
profile settings are merged with the defaults!Content sanitizers'sanitizer'This is anoptionalconfiguration key. A sanitizer can be used to
process submitted values before it is returned by the widget. By default no
processing is performed on submitted values. You can configure a sanitizer
either by providing a function or an importable path to a function, like
so:'sanitizer': lambda value: '<h1>Title</h1>' + valueor:'sanitizer': 'bleach.clean''sanitizer_profiles'This is anoptionalconfiguration key. It is possible to override
the default or configured sanitizer for each of the configuredprofiles.
For example to set a custom sanitizer for theadvancedprofile:'sanitizer_profiles': {
    'advanced': lambda value: value + 'This text has been sanitized.'
}Field & Widget settingsYou can override the default settings per field:class CommentForm(forms.ModelForm):
    content = forms.CharField(widget=RichTextWidget())
    content.widget.field_settings = {'your': 'custom', 'settings': True}or:class Post(models.Model):
    content = RichTextField(
        field_settings={'your': 'custom', 'settings': True},
        sanitizer='bleach.linkify'
    )It’s recommended to useprofiles, they make it easier to switch configs
or even editors on a later date. You use a profile like this:class CommentForm(forms.ModelForm):
    content = forms.CharField(widget=RichTextWidget(field_settings='basic'))or:class Post(models.Model):
    content = RichTextField(field_settings='advanced')NoteFields always inherit the default settings, customs settings and
profiles are merged with the defaults!Custom init / Using another editorIt should be fairly easy to use this project with another editor.
All that’s required is to configureDJRICHTEXTFIELD_CONFIGto load the
right Javascript/CSS files and to create a custominit template.For example, to use jQuery basedSummernote(lite) editor:DJRICHTEXTFIELD_CONFIG = {
    'js': [
        '//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js',
        '//cdnjs.cloudflare.com/ajax/libs/summernote/0.8.9/summernote-lite.js',
    ],
    'css': {
        'all': [
            '//cdnjs.cloudflare.com/ajax/libs/summernote/0.8.9/summernote-lite.css',
        ]
    },
    'init_template': 'path/to/init/summernote.js',
    'settings': {
        'followingToolbar': False,
        'minHeight': 250,
        'width': 700,
        'toolbar': [
            ['style', ['bold', 'italic', 'clear']],
        ],
    }
}Init templateThe init template is a Django template (so it should be in the template and
not in the static directory). It contains a tiny bit of Javascript that’s
called to initialize each editor. For example, the init template for Summernote
would like this:$('#' + id).summernote(settings)The init template has the following Javascript variables available from the
outer scope:fieldDOM node of the textarea to be replacedidTheidattribute of the textareadefault_settingsDJRICHTEXTFIELD_CONFIG['settings']as a JS objectcustom_settingsThefield_settingsas a JS objectsettingsMerge ofdefault_settingsandcustom_settingsHandling uploads & other advanced featuresdjango-richtextfieldbuilt to be editor agnostic. This means that it’s
up to you to handle file uploads, show content previews and support
other “advanced” features.History1.6.1 (2021-04-14)Support Django 3.2 (no changes necessary)Test with Django main (4.0)Use force_str instead of force_text,
the latter is deprecated and removed in Django 4.01.6 (2020-05-20)init.js no longer depends on jQuery.
This might a backwards incompatible change for:Users that have defined their own init script that dependeds on
the$evar. This var has been replaced byfieldwhich is
a plain DOM node instead of a jQuery object.Users that depended on the implicit load of Django’s bundled
version of jQuery now have explicitly load it themselves.Verified TinyMCE init/config works with TinyMCE 4 and 5Tested and verified to work with Django 3.11.5.0 (2019-12-04)Drop support for Python 2Drop support for Django < 2.2Add support for Django 3.01.4.0 (2019-01-31)NOTE: This is the final release that supports Python 2!Add support for plugable server side content sanitizers1.3.0 (2018-11-05)Allow CSS files to be included by aRichTextWidget1.2.4 (2018-09-25)Fix display issue in Django 2.1’s admin interface1.2.3 (2018-09-11)Add support for Django 2.11.2.2 (2018-06-12)Conditionally load the (un)minified version of jquery depending onDEBUGLoad jQuery before all other scripts1.2.1 (2018-01-18)Add['admin/js/vendor/jquery/jquery.min.js', 'admin/js/jquery.init.js']toRichTextWidget.media.js. This makes the widget usable outside of the
admin (but still requiresdjango.contrib.adminto be inINSTALLED_APPS)
and prevents javascript errors inside the admin in certain edge cases.1.2 (2017-12-04)Remove support for Django < 1.11Add support for Django 2.01.1 (2016-01-14)Remove support for Django < 1.8Tested with Django 1.8 & Django 1.91.0.1 (2014-11-13)Fix unicode error1.0 (2014-09-30)First release