There are a lot of WYSIWYG editors available on the internet, some are paid and some are free. After exploring and experimenting with various editors I found tinymce, one of the best WYSIWYG editors. So in this tutorial, I will show how you can install and integrate this editor into your Django admin from scratch.
TinyMCE is a rich-text editor that allows users to create formatted content within a user-friendly interface. With Django admin, it allows developers or users to add rich text directly from the admin panel. Django's default textarea
is replaced by tinymce
widget that transforms it into a WYSIWYG editor.
You can watch this video tutorial also or proceed further.
%[https://youtu.be/636sjoMp_2A]
If you have any confusion about code snippets or directory structure, you can refer to this GitHub repository which contains the source of everything I explain here.
Create a Blog model
For this tutorial, I am creating a blog model
and adding a body
field to add. Later this body
field will be transformed into a WYSIWYG widget. If you already have a model, you can skip this part and consider body
field only.
from django.db import models
class Blog(models.Model):
title = models.CharField(max_length=255, unique=True)
body = models.TextField()
def __str__(self):
return self.title
Run migrations
python manage.py makemigrations
python manage.py migrate
Override admin form for Tinymce widget
Right now in your admin panel, the body
field that you just added as TextField
is rendered as a html textarea element
. By default, it does not have any class associated with it. You have to give a custom className
to this element and later tinymce
will transform it using the className selector
.
You can give any className
. For this tutorial I am naming it richtext_field
.
from django import forms
from .models import *
class BlogAdminForm(forms.ModelForm):
body = forms.CharField(widget=forms.Textarea(attrs={'id': "richtext_field"}))
class Meta:
model = Blog
fields = "__all__"
Include tinymce static files
Now we have the model and class name setup. The next thing you need is to load the static files (CSS, JS) in your admin base template. First, verify your template directory location, mine is set like this.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
To override Django's base template, create a base.html
file inside templates/admin/
.
├── manage.py
├── README.md
├── requirements.txt
├── templates
│  └── admin
│  └── base.html
Now inside the template base.html
, let's add tinymce configuration.
{% extends "admin/base.html" %}
{% load static %}
{% block footer %}
{{ block.super }}
<script src="https://cdn.tiny.cloud/1/YOURAPIKEY/tinymce/5/tinymce.min.js"
referrerpolicy="origin"></script>
<script>
tinymce.init({
selector: '#richtext_field',
plugins: 'print preview importcss tinydrive searchreplace autolink autosave save directionality visualblocks visualchars fullscreen image link media template codesample table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists wordcount imagetools textpattern noneditable help charmap quickbars emoticons blockquote',
menubar: 'file edit view insert format tools table tc help',
toolbar: 'undo redo | bold italic underline strikethrough | fontselect fontsizeselect formatselect | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist checklist | forecolor backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap emoticons | fullscreen preview save print | insertfile image media pageembed template link anchor codesample | a11ycheck ltr rtl | showcomments addcomment',
autosave_ask_before_unload: true,
autosave_interval: '30s',
autosave_prefix: '{path}{query}-{id}-',
autosave_restore_when_empty: false,
autosave_retention: '2m',
image_advtab: true,
automatic_uploads: false,
link_list: [
{title: 'My page 1', value: 'https://www.tiny.cloud'},
{title: 'My page 2', value: 'http://www.moxiecode.com'}
],
image_list: [
{title: 'My page 1', value: 'https://www.tiny.cloud'},
{title: 'My page 2', value: 'http://www.moxiecode.com'}
],
image_class_list: [
{title: 'None', value: ''},
{title: 'Some class', value: 'class-name'}
],
importcss_append: true,
templates: [
{
title: 'New Table',
description: 'creates a new table',
content: '<div class="mceTmpl"><table width="98%%" border="0" cellspacing="0" cellpadding="0"><tr><th scope="col"> </th><th scope="col"> </th></tr><tr><td> </td><td> </td></tr></table></div>'
},
{title: 'Starting my story', description: 'A cure for writers block', content: 'Once upon a time...'},
{
title: 'New list with dates',
description: 'New List with dates',
content: '<div class="mceTmpl"><span class="cdate">cdate</span><br /><span class="mdate">mdate</span><h2>My List</h2><ul><li></li><li></li></ul></div>'
}
],
template_cdate_format: '[Date Created (CDATE): %m/%d/%Y : %H:%M:%S]',
template_mdate_format: '[Date Modified (MDATE): %m/%d/%Y : %H:%M:%S]',
height: 600,
image_caption: true,
quickbars_selection_toolbar: 'bold italic | quicklink h2 h3 blockquote quickimage quicktable',
noneditable_noneditable_class: 'mceNonEditable',
toolbar_mode: 'sliding',
spellchecker_ignore_list: ['Ephox', 'Moxiecode'],
tinycomments_mode: 'embedded',
content_style: '.mymention{ color: gray; }',
contextmenu: 'link image in',
a11y_advanced_options: true,
mentions_selector: '.mymention',
mentions_item_type: 'profile'
});
</script>
{% endblock %}
Set tinymce API KEY
To get your tinymce free APIKEY
. Create an tinymce account if you don't have one. After login:
Step1: Click on *Approved Domain to your left and add localhost and your domain, where you want to add tinymce.
Step2: Click on Dashboard to your left and copy the API KEY
.
Now, that you have your API key, open your base.html
and replace the APIKEY inside the script tag src attribute where it says YOURAPIKEY.
<script src="https://cdn.tiny.cloud/1/YOURAPIKEY/tinymce/5/tinymce.min.js"
referrerpolicy="origin"></script>
<script>
Register blog model
Add your blog model to your admin page. Inside admin.py
register your Blog
model and set the form to the BlogAdminForm
you created few minutes before. This will override Django's default text area with the one you added in the form with the class name.
from django.contrib import admin
from .models import *
from .forms import *
class BlogAdmin(admin.ModelAdmin):
form = BlogAdminForm
admin.site.register(Blog, BlogAdmin)
Now, run your server and visit the blog admin page. Your body field should look like this
Adding Syntax highlighting for tinymce
Now, if you are a developer just like me who want to write their own blog posts then you will have to add code snippets through this tinymce WYSIWYG editor. Now when you render these code snippets in your blog posts, they will not look great. So you have to use some syntax highlighter.
You can render this body field to your templates like this. Make sure you add safe filter.
{{object.body | safe}}
Now add some highlighting to your code snippets. Here is a list of syntax highlighters that you can include in your body and see the magic.
Right now, I am using a prism. But you can use it at your convenience. You have to add the CSS, js files provided by these above websites in your body element. Mine looks like this.
That's all.