Skip to main content

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

 

This tutorial shows how to convert a Flask web application into a desktop application using FlaskWebGUI together with PyInstaller. You will learn how to package your Python code, templates, and database into a standalone executable file. It also covers handling file paths and resolving common issues like missing templates after packaging. By the end, you’ll have a fully functional desktop app that runs without requiring a browser or Python installation. This method is ideal for distributing your Flask projects to end users easily. 

Preliminary 
Before I begin, please activate the virtual environment and install the required dependencies.
python -m venv venv
venv\Scripts\activate
pip install flaskwebgui pyinstaller
Then, we need to set up the file and folder structure, as below:
All files and folders remain the same as in the previous file structure, except that I have added a desktop icon, "my.ico," and amended app.py to convert the Flask script into a GUI script and later packaged the same app into an .exe file and a .db database. 

Step 1: Set up the GUI view from the Flask script
The purpose of installing FlaskWebGui is to create desktop applications with Flask; therefore, it is similar to Electron.js but built on the Flask Python framework. 

Below I have shown my code:
from flask import (Flask, render_template, redirect, 
                   url_for)
from form import ContactForm
from flask_ckeditor import CKEditor
import sqlite3
from flaskwebgui import FlaskUI as ui
import os
import sys
import sqlite3

db_path = os.path.join(os.getcwd(), "flask_ckeditor_desktop/message.db")

conn = sqlite3.connect(db_path)

conn.execute("""
CREATE TABLE IF NOT EXISTS message (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT,
    email TEXT,
    subscribe TEXT,
    message TEXT
)
""")
conn.commit()

app = Flask(__name__)

app.config['SECRET_KEY'] = 'mysecretkey'
app.config['CKEDITOR_PKG_TYPE'] = 'full-all'

ckeditor = CKEditor(app)

@app.route('/')
def index():
    form = ContactForm()
    return render_template('contact.html', form=form)

@app.route('/message', methods=['GET','POST'])
def submit():
    form = ContactForm()
    
    if form.validate_on_submit():
        name = form.name.data
        email = form.email.data
        subscribe = form.subscribe.data
        message = form.message.data
        
        db_path = os.path.join(os.getcwd(), "message.db")
        conn = sqlite3.connect(db_path)
        
        c = conn.cursor()
        try:
            query = ("""INSERT INTO message
                        VALUES (:id, :name, :email, :subscribe, :message)""")

            my_data = {
                'id' : None,
                'name': name,
                'email': email,
                'subscribe': subscribe,
                'message': message
                }
         
            content = c.execute(query, my_data)
            conn.commit()

            print(f"Data Added ID: " + str(content.lastrowid))

        except sqlite3.Error as e:
            print(e)
       
        return redirect(url_for('thankyou'))
    
    return render_template('contact.html', form=form)
    
@app.route('/thankyou')
def thankyou():
    return render_template('thankyou.html')
    
if __name__ == '__main__':
    ui(app=app, server="flask", width=1000, height=1000).run()
In the previous tutorial, I separated the creation of the SQLite database.db from app.py; however, for simplicity in this tutorial, I will combine the creation of the SQLite database into app.py.

What I do is import the FlaskWebGUI UI component and use it to show the dimensions of the app, such that both height and width are 1,000, and use the Flask web framework for GUI creation (last line of the Flask app).

Then, I will launch the app by inputting the following code in the terminal.
python flask_ckeditor/app.py
Once the message.db is created, now I can comment on the following code since I don't need it anymore:
# conn = sqlite3.connect(db_path)

# conn.execute("""
#CREATE TABLE IF NOT EXISTS message (
#    id INTEGER PRIMARY KEY AUTOINCREMENT,
#    name TEXT,
#    email TEXT,
#    subscribe TEXT,
#    message TEXT
#)
#""")
#conn.commit()

Step 2: Package the Flask script into a .exe and .db files using PyInstaller
If I need to distribute the desktop application, I need to package it before it is ready to use. PyInstaller is dependent on the respective operating system (OS); Windows has .exe, and macOS has .app, respectively. Since my computer is running Windows OS, I installed PyInstaller to package my Flask script and convert it into a .exe Windows executable file. Before packaging, 

I need to amend the Flask script so PyInstaller knows where to locate the other folder and file; this is important to avoid the error "TemplateNotFound." So, the following shows how I amended the Flask code:
def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

app = Flask(
    __name__,
    template_folder=resource_path("templates")
)
The resource_path() is a dynamic file locator; it helps to locate the Flask templates, static folder, and database. In my case, it is a SQLite database. This will prevent common PyInstaller errors. After I had amended the above code, I could package it by following the code in the PowerShell terminal.
pyinstaller --onefile --noconsole `
--add-data "flask_ckeditor_desktop\templates;templates" `
--add-data "flask_ckeditor_desktop\message.db;." `
--icon "Flask_ckeditor_desktop\my.ico" `
flask_ckeditor_desktop\app.py
1) pyinstaller: run the PyInstaller,

2) --onefile: that PyInstaller extracts the file into one single .exe file. 

3) --nonconsole: Console is helping us to display the error and debugging; however, here I choose to hide the 'black terminal' if I am satisfied that the application runs successfully.

4) --add-data "flask_ckeditor_desktop\templates": Request the PyInstaller from the flask_ckeditor_desktop folder and find the contact.html and thankyou.html files to include in the .exe folder. 

5) --add-data "flask_ckeditor_desktop\message.db": Request the PyInstaller from the flask_ckeditor_desktop folder and find the message.db file to include in the .exe folder. 

6) --icon "Flask_ckeditor_desktop\my.ico": Requests the PyInstaller from the Flask_ckeditor_desktop folder, finds the desktop icon to include in the .exe folder, and shows the icon as a desktop shortcut. 

7) Flask_ckeditor_desktop\app.py: Requests PyInstaller from the Flask_ckeditor_desktop folder to find the Flask main entry file. Thus, PyInstaller starts from here and bundles everything needed.

The app.exe output file will appear in the dist folder.

Here is my result for the app.exe Windows executable file:

Final wrap-up: 
In this tutorial, you learned how to transform a Flask web application into a standalone desktop app using FlaskWebGUI and PyInstaller. You explored how to bundle templates, configure file paths correctly, and customise your executable with an icon. Key challenges like missing templates and database handling were also addressed. By applying these steps, you can confidently package and distribute your Flask apps as user-friendly desktop applications.

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 Contact Form for SME Systems with Flask CKEditor (Part 3)

  In the previous tutorial, I used TinyDB as our storage solution to keep application data in a simple JSON-based format. While TinyDB is lightweight and easy to use, many web applications require a more structured and scalable database system. In this tutorial, we will switch to SQLite , a powerful relational database that integrates well with Python and web frameworks. By using SQLite, you will learn how to store, manage, and query data in a more structured way for real-world applications. Preliminary Before I begin, please activate the virtual environment and install the required dependencies. Since SQLite is part of the Python standard library, it is pre-installed. python -m venv venv venv\Scripts\activate pip install flask Then, we need to set up the file and folder structure, as below: Question 1: What is SQLite? SQLite is a lightweight, serverless relational database that stores data in a single file on your computer. Unlike traditional database systems, it does ...

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...