Adding A Text Editor To Your Admin Console (TinyMCE)


April 29, 2023 • Python Django HTML CSS Tailwind TinyMCE



Adding posts of any kind to your website can be done in many different ways. Assuming you use some for of database, in my case SQLite, to store data on your site, the best way to add new posts is through an admin console. My site uses Django and Tailwind for styling and I have implemented a lightweight editor called TinyMCE to make my life easier when editing and creating posts.

 

Key features implemented into the editor:

 

 

Setting Up TinyMCE

 

Luckily setting up TinyMCE is quite simple with a few steps. The first thing you want to do is install django-tinymce and initialize tinyMCE. To install django-tinymce use the following command (for me I use a venv so I install the package in my venv).

 

pip install django-tinymce

 

Once you do this, you need to add this as an app to your website, so in settings.py under installed apps you want to add the following.

 

'tinymce',

 

The last step needed is to add the following to the models.py file of the app you want to be able to use the editor on. The following code is an example of how it can be setup depending on what field you want the editor in.

 

from django.db import models

from tinymce import models as tinymce_models

# Create your models here.
class Category(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Post(models.Model):
    title = models.CharField(max_length=255)
    slug = models.CharField(max_length=255, default="")
    body = tinymce_models.HTMLField()
    created_on = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)
    categories = models.ManyToManyField('Category', related_name='posts')

    def __str__(self):
        return self.title

class Comment(models.Model):
    author = models.CharField(max_length=60)
    body = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    post = models.ForeignKey('Post', on_delete=models.CASCADE)

 

There are 2 lines in the code above that need to be altered from the standard models code you may have setup already. Line 2 (from tinymce import models as tinymce_models) needs to be added and the variable that would contain the text you want edited needs to be altered, line 15(body = tinymce_models.HTMLField()).

 

Remember, once you change models.py in any way you want to make the migrations so use the following 2 commands.

 

python manage.py makemigrations

python manage.py migrate

 

Once this is done the default TinyMCE should be working! We want more of course so let's make this editor more customized!

 

 

Customizing The TinyMCE Editor

 

My website has a decently complex editor that has all the essentials including code samples which I needed for most of my blogs and projects displayed on my site. In order to make the changes, we are going to add a new folder and file in the base directory and call it admin templates. It will look something like this:

 

admin_templates/admin/change_form_object_tools.html

 

Then once you have this open add the following just above the endblock on the last line.

 

<script src="https://cdn.tiny.cloud/1/apikey/tinymce/5/tinymce.min.js"
            referrerpolicy="origin"></script>
    <script>

        tinymce.init({
            selector: 'textarea',
            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 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,
            codesample_dialog_height: 300,
            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',
            codesample_languages: [
                {text: 'HTML/XML', value: 'markup'},
                {text: 'JavaScript', value: 'javascript'},
                {text: 'CSS', value: 'css'},
                {text: 'PHP', value: 'php'},
                {text: 'Ruby', value: 'ruby'},
                {text: 'Python', value: 'python'},
                {text: 'SQL', value: 'sql'},
                {text: 'Java', value: 'java'},
                {text: 'C', value: 'c'},
                {text: 'C#', value: 'csharp'},
                {text: 'C++', value: 'cpp'}
            ],
        });
    </script>

 

This will add a bunch of new features like being able to add images, code samples, and tables. Once thing will not work without a couple more steps and that is the code samples.

 

Before it works, the last thing you want to do is change something in settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'admin_templates')], #This line here
        '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',
                'theme.context_processors.theme',
            ],
        },
    },
]

Add os.path.join(BASE_DIR, 'admin_templates') and you will be good to go!

 

 

Adding Better Code Sample Support

 

To add support for code samples added above, first thing you want to do is go to https://prismjs.com/download.html or to add the defaults to the douwnload right away go to https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript and get the proper download files that fits your needs.

 

Once you get the files you can either have them saved in a local file and access them that way or use a CDN like jsDelivr like I did to hold the files. Either way you will need to add the stylesheet and script to the base.html file. The two lines you want to add are the following.

 

<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/the-jolley-boy/static-files/static/prism.css">
<script src="https://cdn.jsdelivr.net/gh/the-jolley-boy/static-files/static/prism.js"></script>

 

Once this is done then you are ready to go and adding content to your website will be so much easier!

 

One thing to note is to have proper formatting on the website you want to use safe when accessing data from the database. Look below for an example.

 

{{ post.body | safe}}



Leave a comment:




Comments: