
Django - CKEditor, CodeSnippet, Highlight.js & Youtube
Installation
Install django-editor package:
pip install django-ckeditor
Add ckeditor to the INSTALLED_APPS list in settings.py:
INSTALLED_APPS = [
...
'ckeditor',
]
Add RichTextField
Add a field to some of your models:
from ckeditor.fields import RichTextField
description = RichTextField(blank=True, null=True)
Run migrations:
python manage.py makemigrations && python manage.py migrate
Now you can use the wysiwyg editor in the Admin area when using the description field.
Serving Static Files In Development And Production
CKEDitor static assets (js, css) are loaded automatically when we are using the development server.
If you have django.contrib.staticfiles listed in the INSTALLED_APPS list, then Django will serve the static files automatically in DEBUG mode.
But in production, you should define STATIC_URL and STATIC_ROOT...
STATIC_URL = '/static/'
STATIC_ROOT = '/home/mysite/static/'
...and run python manage.py collectstatic to collect the resources to the STATIC_ROOT folder.
In Nginx you could add a these lines to the nginx configuration file to serve static and media files:
location /static/ {
alias /home/mysite/static/;
}
location /media/ {
alias /home/mysite/media/;
}
How To Upload Files
Add ckeditor_uploader and CKEDITOR_UPLOAD_PATH to the settings file:
INSTALLED_APPS = [
...
'ckeditor',
'ckeditor_uploader', # < here
]
CKEDITOR_UPLOAD_PATH = "uploads/" # < here
Include CKEditor urls in the main urls.py file:
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('base.urls')),
path('ckeditor/', include('ckeditor_uploader.urls')), # < here
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Make sure to serve user uploaded media files in development by adding this to urlpatterns:
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
And defining these in the settings.py file:
MEDIA_URL = '/media/'
MEDIA_ROOT = 'media/'
For file uploads we have to change the field type to RichTextUploadingField:
# description = RichTextField(blank=True, null=True)
description = RichTextUploadingField(blank=True, null=True)
Run migrations:
python manage.py makemigrations && python manage.py migrate
Go to the admin area and you should be able to upload images with the description field.
Use the safe filter in templates to show all the HTML markup:
{{ post.description | safe }}
Custom Forms
Create forms.py file inside some app folder. I will be using the blog app.
Add these lines in it:
from django.forms import ModelForm
from .models import Post
class PostForm(ModelForm):
class Meta:
model = Post
fields = ['description']
Edit main urls.py file and add these lines:
from blog import views as blog_views # < here
path('ckeditor/', include('ckeditor_uploader.urls')),
path('add/post/', blog_views.add_post, name='add_post'), # < here
path('edit/post/<int:post_id>/', blog_views.edit_post, name='edit_post'), # < here
Edit the blog app views.py file and add these lines:
from django.shortcuts import render
from .forms import PostForm
def add_post(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
post_item = form.save(commit=False)
post_item.save()
return redirect('/')
else:
form = PostForm()
return render(request, 'blog/post_form.html', {'form': form})
Create the form template in /blog/templates/blog/post_form.html:
<form method="POST" action="">
{% csrf_token %}
{{ form.media }}
{{ form }}
<input type="submit" value="Save">
</form>
Now you can add posts in /add/post/.
Edit main urls.py file and add this line:
from blog import views as blog_views
path('ckeditor/', include('ckeditor_uploader.urls')),
path('add/post/', blog_views.add_post, name='add_post'),
path('edit/post/<int:post_id>/', blog_views.edit_post, name='edit_post'), # < here
Edit the blog app views.py file and add these:
def edit_post(request, post_id=None):
item = get_object_or_404(Post, id=post_id)
form = PostForm(request.POST or None, instance=item)
if form.is_valid():
form.save()
return redirect('/')
return render(request, 'blog/post_form.html', {'form': form})
Now you can edit posts in /edit/post/[id]/.
Custom Configuration
You can customize the toolbar with CKEDITOR_CONFIGS dictionary.
Put this in the settings.py file:
CKEDITOR_CONFIGS = {
'default': {
'toolbar': 'Custom',
'toolbar_Custom': [
['Bold', 'Link', 'Unlink', 'Image'],
],
}
}
Now by default you have just these 4 options in the toolbar.
Check the https://docs.ckeditor.com/ckeditor4/latest/api/CKEDITOR_config.html#cfg-height for more configuration options.
Here I change the height to 500 px:
CKEDITOR_CONFIGS = {
'default': {
'toolbar': 'Custom',
'height': 500, # < here
'toolbar_Custom': [
['Bold', 'Link', 'Unlink', 'Image'],
],
}
}
You can define multiple configurations like this:
CKEDITOR_CONFIGS = {
'default': {
'toolbar': 'Custom',
'height': 500,
'toolbar_Custom': [
['Bold', 'Link', 'Unlink', 'Image'],
],
},
'special': {
'toolbar': 'Special',
'toolbar_Special': [
['Bold'],
],
}
}
And then define the configuration in models.py:
description = RichTextUploadingField(blank=True, null=True)
description2 = RichTextUploadingField(blank=True, null=True, config_name='special') # < here
Run migrations:
python manage.py makemigrations && python manage.py migrate
Now the first description field gets the default settings and description2 field gets our special configuration.
You can find the default Full toolbar in the widgets.py file:
vim venv/lib/python3.6/site-packages/ckeditor/widgets.py
Here we use the default Full toolbar options for our Custom toolbar:
CKEDITOR_CONFIGS = {
'default': {
'toolbar': 'Custom',
'height': 500,
'toolbar_Custom': [
['Styles', 'Format', 'Bold', 'Italic', 'Underline', 'Strike', 'SpellChecker', 'Undo', 'Redo'],
['Link', 'Unlink', 'Anchor'],
['Image', 'Flash', 'Table', 'HorizontalRule'],
['TextColor', 'BGColor'],
['Smiley', 'SpecialChar'], ['Source'],
],
},
'special': {
'toolbar': 'Special',
'toolbar_Special': [
['Bold'],
],
}
}
Extra Plugins (CodeSnippet)
The package ships with some extra plugins that are not enabled by default.
Here is an example how to enable CodeSnippet syntax highlighter:
'special': {
'toolbar': 'Special',
'toolbar_Special': [
['Bold'], ['CodeSnippet'], # < here
],
'extraPlugins': 'codesnippet', # < here
}
Now you should have a CodeSnippet icon in the Special toolbar.
You also need some syntax highlighter. My personal favourite https://highlightjs.org/.
Add this to your html head section:
<link rel="stylesheet"
href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script src="/static/base/js/main.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
Now you should see the syntax highlighting working when you print out the field in templates like this:
{{ post.description2 | safe }}
Custom Plugins (Youtube)
Here is how you can add more plugins.
Use external_plugin_resources in models.py:
description2 = RichTextUploadingField(blank=True, null=True,
config_name='special',
external_plugin_resources=[(
'youtube',
'/static/base/vendor/ckeditor_plugins/youtube/youtube/',
'plugin.js',
)],
)
In this example we add the https://ckeditor.com/cke4/addon/youtube.
Download the plugin and put it in some app's static folder. In here I use the base app. I put external libraries in the vendor folder:
cd base/static/base/vendor
mkdir -p ckeditor_plugins/youtube
cd ckeditor_plugins/youtube
wget https://download.ckeditor.com/youtube/releases/youtube_2.1.10.zip --no-check-certificate
unzip youtube_2.1.10.zip
rm youtube_2.1.10.zip
Enable the plugin in the settings.py file:
'special': {
'toolbar': 'Special',
'toolbar_Special': [
['Bold'], ['CodeSnippet', 'Youtube'],
],
'extraPlugins': ','.join(['codesnippet', 'youtube']),
}
And now you can also embed youtube videos.
Comments
thanks
How do you add the spellchecker 'scayt'? I've added it using the 'extraPlugins', but it doesn't show up in the toolbar...