TinyMCE and Flask

Posted on by Kevin Foong

In this post I will run through process of setting up the TinyMCE editor with Flask. TinyMCE is a great WYSIWYG editor and suitable for things like blog posts. It also enables you to upload images directly into your text.

Follow the instructions below to set up TinyMCE as a local download.

  1. In Flask I create my forms as per normal using Flask-WTF
    class PostForm(FlaskForm):
        heading = StringField('Title', validators=[InputRequired(), Length(max=100)])
        post = TextAreaField('Write something')
        tags = StringField('Tags')
        submit = SubmitField('Submit')​
  2. Note that the post field is defined as a TextAreaField. Later we will be using the TinyMCE editor to replace this field.

  3. Now download TinyMCE (see
    and unzip the contents into a web accessible location. I downloaded mine into a folder named "tinymce" under the static folder.

    In the template which contains the form, you will need to include the TinyMCE script and initialise it (see below). As you can see there are a lot of options. The important one to take note for now is selector which will point to the id of the textarea we defined in step 1. We know it is post because that is the name of field we defined in step 1. Flask will automatically set the id of each element to the name of the field. 
    <script type="text/javascript" src="{{ url_for('static', filename='tinymce/tinymce.min.js') }}"></script>
    <script type="text/javascript">
        selector: '#post',
        plugins: [
          'advlist autolink link image imagetools lists charmap print preview hr anchor pagebreak spellchecker',
          'searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking',
          'save table contextmenu directionality template paste textcolor codesample'
        imagetools_toolbar: "rotateleft rotateright | flipv fliph | editimage imageoptions",
        toolbar: 'insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image | print preview media fullpage | forecolor backcolor emoticons | codesample',
        images_upload_url: '{{ url_for('imageuploader') }}',
        automatic_uploads: true,
        images_reuse_filename: false,
        images_upload_base_path: '/static/uploads',
        codesample_languages: [
          {text: 'HTML/XML', value: 'markup'},
          {text: 'JavaScript', value: 'javascript'},
          {text: 'CSS', value: 'css'},
          {text: 'Processing', value: 'processing'},
          {text: 'Python', value: 'python'}
  4. At this stage when you run your app, the TinyMCE editor should appear in place of the TextAreaField. You will now be able to use the TinyMCE editor and all its features. Then when you are finished editing and click submit, the HTML you entered, will be automatically set back to the original TextAreaField and written to the database as normal. Flask does not even need know that you were using TinyMCE.

  5. You can also upload images directly into TinyMCE. images_upload_url was defined in step 3 which refers to function imageuploader. We now need to define this function. This function basically saves the image on the server and appends the image link back into the TinyMCE editor.
    @app.route('/imageuploader', methods=['POST'])
    def imageuploader():
        file = request.files.get('file')
        if file:
            filename = file.filename.lower()
            if ext in ['jpg', 'gif', 'png', 'jpeg']:
                img_fullpath = os.path.join(app.config['UPLOADED_PATH'], filename)
                return jsonify({'location' : filename})
        # fail, image did not upload
        output = make_response(404)
        output.headers['Error'] = 'Image failed to upload'
        return output

That's it!

Some additional ideas includes saving a thumbnail version of the image and saving the image metadata (such as file name, width x height, file size) into a database. Both of these can be accomplished with the help of the Pillow library. I may write another tutorial on this in another post. Meanwhile if you have any comments do let me know. 

You can see the full source code on Github

Update - I have now also written part 2 here.

Tags: tinymce, flask, python


Kevin Foong on

I took a look and you are missing the closing bracket for codesample_languages. Should be: codesample_languages: [ {text: 'HTML/XML', value: 'markup'}, {text: 'JavaScript', value: 'javascript'}, {text: 'CSS', value: 'css'}, {text: 'Processing', value: 'processing'}, {text: 'Python', value: 'python'} ], content_css: [ '//,300i,400,400i', '//' ]

Edvin Dunaway on

I'm not able to get it to work with my site. could you look?

Email is optional