Skip to main content

How to Build a Contact Form for SME Systems with Flask CKEditor (Part 2)

TinyDB

In Part One, we built and styled our contact form using Flask and CKEditor. Now in Part Two, we’ll take it a step further by connecting the form to TinyDB so we can actually store user submissions.

In this tutorial, you’ll learn how to save form data into a JSON database, handle validation properly, and implement a clean redirect after submission. By the end, your contact form won’t just collect messages—it will securely store them like a real web application.

Preliminary
Before I begin, it is recommended that you activate the virtual environment and install the relevant dependencies.
python -m venv venv
venv\Scripts\activate 
pip install flask tinydb
Then, we need to set up the file and folder structure, as below:

TinyDB

Everything is the same as in part one, the templates folder, except for contact.html, which will now add a new thankyou.html. On the other hand, I need to amend the form.py and add two new routes to streamline the form submission in app.py! 

In fact, TinyDB is a non-schema database storage, and it stores all the input data in JSON format. Therefore, when the submission button is clicked, the data will be automatically stored in the message.json, as shown in the above diagram. 

The benefits are as follows:
  1. TinyDB is a pure Python database that stores data in a simple JSON file.
  2. It feels like working with Python dictionaries and lists.
  3. TinyDB is small and fast for low to medium data volumes.
  4. All data is stored in a readable .json file.
  5. You don’t need to learn SQL queries.
  6. TinyDB works smoothly inside Flask apps without needing external database services like MySQL or PostgreSQL

Step 1: Amend the form.py
from flask_wtf import FlaskForm
from wtforms import StringField, BooleanField, SubmitField
from wtforms.validators import DataRequired
from flask_ckeditor import CKEditorField

class ContactForm(FlaskForm):
    name = StringField('Name:', validators=[DataRequired()])
    email = StringField('Email:', validators=[DataRequired()])
    subscribe = BooleanField("Subscribe to our newsletter?")
    message = CKEditorField('Message:', validators=[DataRequired()])
    submit = SubmitField("Submit ☺️")
In order to ensure the message field is accepted and validated under the WTF. I need to import the CKEditorField, assign it to the message field, and set the validator as data required.


Step 2: Update the submission form
Once I have amended the form.py, I need to update it on contact.html, as below:
<form method="POST" action="{{ url_for('submit') }}">
    {{ form.hidden_tag() }}

    <p>{{ form.name.label }} {{ form.name(size=32) }}</p>
    <p>{{ form.email.label }} {{ form.email(size=32) }}</p>
    <p>{{ form.message.label }} {{ form.message() }}</p>

    {{ ckeditor.load() }}
    {{ ckeditor.config(name='message') }}

    <p>{{ form.subscribe() }} {{ form.subscribe.label }}</p>
    <p class="submit-container">{{ form.submit(class="btn-submit") }}</p>
</form>
The form action refers to the submit() function on the app.py (we will set it up later on), and I am also adding an additional 'form.message()' widget on the contact.html. 

Even though I need to create a rich text editor by creating the ckeditor.load(). However, the 'form.message()' widget originally refers to a textarea by default. Therefore, when I coded a ckeditor.config with name='message', the purpose was to allow the rich text editor to replace the existing textarea widget display. 


Step 3: Set up the submit() function
Now I need to create the Submit() function as follows:
from flask import (Flask, render_template, redirect, 
                   url_for)
from tinydb import TinyDB

# The JSON file output path
db = TinyDB('flask_ckeditor/message.json')

def submit():
    # Create an instance of the ContactForm
    form = ContactForm()
    
    # Check if the form is submitted and passes validation
    
    if form.validate_on_submit():
    # Retrieve data from each form field
        name = form.name.data
        email = form.email.data
        subscribe = form.subscribe.data
        message = form.message.data
        
        # Insert the form data into the database
        db.insert({
            'name': name,
            'email': email,
            'subscribe': subscribe,
            'message': message
        })
        
        # Redirect the user to the thank you page after successful submission
        return redirect(url_for('thankyou'))
   
   # If form is not submitted or validation fails,
   # re-render the contact page and display validation errors
   return render_template('contact.html', form=form)
Let me import the relevant libraries and set the output path of message.json

What I did here:
1) I need to validate all the input fields (data required), such as name, email, subscribe, and message.
2) After validation, I need to add those input fields to the message.json database.
3) If the form is accepted and validated, the app will now redirect to the thankyou() function.
4) Otherwise, it will re-render on the same page.

The formatted message.json is as follows:
Json Formatter



Step 4: Set up the thankyou() function and thankyou.html
This function is to inform the user that the message was added successfully. 
The thankyou() is as follows:
@app.route('/thankyou')
def thankyou()
   # render to thankyou page
    return render_template('thankyou.html')
The thankyou.html is as follows:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Submitted Successfully</title>
  <style>
    h1 {
      colour: red;
      text-align: centre;
      font-family: Arial, sans-serif;
    }
  </style>
</head>
<body>
  <h1>Your message has been sent successfully! 😊</h1>
</body>
</html>
Here is the thankyou.html view:
thankyou.html

Bonus
If you need to view the details of the output on the terminal, simply add this line of code
print(db.all())

The details on the terminal are as follows:
Show a details




Final wrap-up:
We’ve now connected our Flask contact form to TinyDB and can store messages in a JSON file. The form validates input with Flask-WTF and uses CKEditor for rich text messages.
Submissions are saved securely, and users see a thank-you page after sending.
This setup makes your contact form fully functional and ready for small web apps or projects.

⬅ Previous Part                                                                                                                                        ➡ Next Part                                      


To view the full code, please click here

Comments

Popular Posts

How to Design a Location Tracking Module for Desktop Business Systems Using Python?

This tutorial will show you how to create an interactive map application that allows users to input geographic coordinates and visualize locations on an interactive map using Python's Tkinter GUI framework enhanced with TTKBootstrap styling and the TkinterMapView widget.  Preliminary   Before I begin, it is recommended to activate the virtual environment before installing the relevant dependencies. python -m venv venv venv\Scripts\activate pip install ttkbootstrap tkintermapview As usual, we need to import the relevant module and set the root values from tkinter import * import ttkbootstrap as tb import tkintermapview from ttkbootstrap.dialogs import Messagebox root = tb.Window(themename='darkly') root.title('Find My Map') root.geometry("1200x1200") I would like to divide it into three sections.  a) Input Panel Layout,  The headers are mainly a label with a map emoji.  The main layout contains labels and input fields for latitude and longitude, ...

How to build a Desktop Business System for Audiobook Workflow Management with Python?

In this tutorial, we will build a simple audiobook player using Python and CustomTkinter. You will learn how to convert text into speech using gTTS and play it with PyGame. We will also implement play, pause, and stop controls, like those in a real audio player. By the end, you will have a clean and functional desktop audiobook app. Preliminary   Before I begin, it is recommended to activate the virtual environment before installing the relevant dependencies. python -m venv venv venv\Scripts\activate pip install customtkinter pillow gTTS pygame CTkMessagebox pypdf Then, the following steps include setting up the file structure, app.py, and two additional folders: the uploads and media folders. The media folder contains the icons necessary to build the app; there are read, pause, and stop icons, as shown on the diagram. Step 1: Build up the app interface I have 4 sections here: the header, upload area, text body, and button group.  (a) The header—this section is basicall...

How to Build a Contact Form for SME Systems with Flask CKEditor (Part 1)

In this tutorial, we will be integrating Flask-WTF and Flask-CKEditor into your Flask application! You'll learn how to set up the editor, securely handle the formatted HTML content, and create a seamless user experience that enhances any project requiring user-generated content. Let's get started! Preliminary Before I begin, it is recommended to activate the virtual environment before installing the relevant dependencies. python -m venv venv venv\Scripts\activate pip install flask flask-wtf flask-ckeditor The next step is to set up an app structure; they are app.py, form.py, and the templates folder. Within the templates folder is contact.html. The app structure is described in the following diagram: Step 1: Create the basic minimum file configuration Let us set up the app.py by importing the necessary module and configuration. from flask import Flask, render_template app = Flask(__name__) app.config['SECRET_KEY'] = 'mysecretkey' @app.route('/...