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.
PreliminaryBefore 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: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:
- TinyDB is a pure Python database that stores data in a simple JSON file.
- It feels like working with Python dictionaries and lists.
- TinyDB is small and fast for low to medium data volumes.
- All data is stored in a readable
.jsonfile. - You don’t need to learn SQL queries.
- 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)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:
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:

Bonus
If you need to view the details of the output on the terminal, simply add this line of code
print(db.all())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.
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.
To view the full code, please click here




Comments
Post a Comment