A Django model field and widget that renders a customizable WYSIWYG/rich text editor
Project description
A Django model field and widget that renders a customizable rich text/WYSIWYG widget.
Works in Django’s admin interface and “normal” forms.
Supports global editor settings, reusable editor profiles and per field & widget settings. There’s built-in support for pluggable server side content sanitizers.
Tested with TinyMCE and CKEditor. Designed to be easily extended to use other editors.
Quickstart
Install django-richtextfield and add it to your Django project’s INSTALLED_APPS, django.contrib.admin must also be in INSTALLED_APPS:
INSTALLED_APPS = [ 'django.contrib.admin', ... 'djrichtextfield' ]
Add the urls to the project’s urlpatterns:
path('djrichtextfield/', include('djrichtextfield.urls'))
Configure django-richtextfield in settings.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 include form.media in the <head> of the template:
<head> ... {{ form.media }} ... </head>
Configuration
Define the DJRICHTEXTFIELD_CONFIG dictionary 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 your STATIC_URL e.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 your STATIC_URL e.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 the init template for your editor. Currently django-richtextfield ships with two templates, either:
'init_template': 'djrichtextfield/init/tinymce.js'
or:
'init_template': 'djrichtextfield/init/ckeditor.js'
Editor settings
- 'settings'
A Python dictionary with the default configuration 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 an optional configuration 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' } }
Content sanitizers
- 'sanitizer'
This is an optional configuration 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>' + value
or:
'sanitizer': 'bleach.clean'
- 'sanitizer_profiles'
This is an optional configuration key. It is possible to override the default or configured sanitizer for each of the configured profiles. For example to set a custom sanitizer for the advanced profile:
'sanitizer_profiles': { 'advanced': lambda value: value + 'This text has been sanitized.' }
Field & Widget settings
You 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 use profiles, 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')
Custom init / Using another editor
It should be fairly easy to use this project with another editor. All that’s required is to configure DJRICHTEXTFIELD_CONFIG to load the right Javascript/CSS files and to create a custom init template.
For example, to use jQuery based Summernote (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 template
The 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:
- field
DOM node of the textarea to be replaced
- id
The id attribute of the textarea
- default_settings
DJRICHTEXTFIELD_CONFIG['settings'] as a JS object
- custom_settings
The field_settings as a JS object
- settings
Merge of default_settings and custom_settings
Handling uploads & other advanced features
django-richtextfield built to be editor agnostic. This means that it’s up to you to handle file uploads, show content previews and support other “advanced” features.
History
1.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 $e var. This var has been replaced by field which 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 5
Tested and verified to work with Django 3.1
1.5.0 (2019-12-04)
Drop support for Python 2
Drop support for Django < 2.2
Add support for Django 3.0
1.4.0 (2019-01-31)
NOTE: This is the final release that supports Python 2!
Add support for plugable server side content sanitizers
1.3.0 (2018-11-05)
Allow CSS files to be included by a RichTextWidget
1.2.4 (2018-09-25)
Fix display issue in Django 2.1’s admin interface
1.2.3 (2018-09-11)
Add support for Django 2.1
1.2.2 (2018-06-12)
Conditionally load the (un)minified version of jquery depending on DEBUG
Load jQuery before all other scripts
1.2.1 (2018-01-18)
Add ['admin/js/vendor/jquery/jquery.min.js', 'admin/js/jquery.init.js'] to RichTextWidget.media.js. This makes the widget usable outside of the admin (but still requires django.contrib.admin to be in INSTALLED_APPS) and prevents javascript errors inside the admin in certain edge cases.
1.2 (2017-12-04)
Remove support for Django < 1.11
Add support for Django 2.0
1.1 (2016-01-14)
Remove support for Django < 1.8
Tested with Django 1.8 & Django 1.9
1.0.1 (2014-11-13)
Fix unicode error
1.0 (2014-09-30)
First release
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.