Simple Feedback System In Python Flask (Free Download)

Welcome to a tutorial on how to create an online feedback system with Python Flask and SQLite. Need to collect some feedback or suggestions from the users? Do a quick survey? Here’s how we can build a simple feedback system – Read on!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TABLE OF CONTENTS

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

  • Create a project folder, e.g. D:\feedback, unzip the code inside this folder.
  • Navigate to the project folder in the command line cd D:\feedback, create a virtual environment to not mess up your other projects.
    • virtualenv venv
    • Windows – venv\scripts\activate
    • Mac/Linux – venv/bin/activate
  • Get all the required packages – pip install flask
  • Create the database python S1B_create.py
  • Launch! python S3_server.py and access http://localhost.
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

SCREENSHOT

 

EXAMPLE CODE DOWNLOAD

Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

 

PYTHON ONLINE FEEDBACK

All right, let us now walk through the steps of building an online feedback system with Flask and SQLite.

 

STEP 1) THE DATABASE

1A) FEEDBACK TABLE

S1A_feedback.sql
-- (A) FEEDBACK
CREATE TABLE `feedback` (
  `feedback_id` INTEGER NOT NULL,
  `feedback_title` TEXT NOT NULL,
  `feedback_desc` TEXT DEFAULT NULL,
  PRIMARY KEY("feedback_id" AUTOINCREMENT)
);

This should be self-explanatory, the “main feedback table”.

  • feedback_id Primary key, auto-increment.
  • feedback_title Title of the feedback form.
  • feedback_desc Description of the feedback form, optional.

 

1B) FEEDBACK QUESTIONS

S1A_feedback.sql
-- (B) FEEDBACK QUESTIONS
CREATE TABLE `feedback_questions` (
  `feedback_id` INTEGER NOT NULL,
  `question_id` INTEGER NOT NULL,
  `question_text` TEXT NOT NULL,
  `question_type` TEXT NOT NULL DEFAULT 'R',
  PRIMARY KEY ("feedback_id","question_id")
);

Next, we have a table to hold the questions of the feedback form.

  • feedback_id Composite primary and foreign key.
  • question_id Composite primary key.
  • question_text The question itself.
  • question_type Type of question, for this example:
    • R Rating (1 to 5).
    • O Open text (user can enter anything).

Feel free to invent your own question_type as required. For example, maybe D for a dropdown selector.

 

 

1C) USER FEEDBACK

S1A_feedback.sql
-- (C) FEEDBACK FROM USERS
CREATE TABLE `feedback_users` (
  `user_id` INTEGER NOT NULL,
  `feedback_id` INTEGER NOT NULL,
  `question_id` INTEGER NOT NULL,
  `feedback_value` TEXT NOT NULL,
  PRIMARY KEY ("user_id","feedback_id","question_id")
);

A table to store the feedback from the users.

  • user_id Composite primary and foreign key. This should tie into your existing user system. If you want to open it for public feedback, check out the extras section below.
  • feedback_id Composite primary and foreign key.
  • question_id Composite primary and foreign key.
  • feedback_value Feedback as entered by the user.

 

1D) DUMMY FEEDBACK FORM

S1A_feedback.sql
-- (D) DUMMY FEEDBACK FORM
INSERT INTO `feedback`
  (`feedback_title`, `feedback_desc`)
VALUES
  ("XYZ Course Feedback", "Optional Description.");
 
INSERT INTO `feedback_questions`
  (`feedback_id`, `question_id`, `question_text`, `question_type`)
VALUES
  (1, 1, "Are the course materials sufficient?", "R"),
  (1, 2, "How likely are you to recommend this course to friends?", "R"),
  (1, 3, "Any other feedback on the course?", "O");

Lastly, a dummy example to better illustrate how the tables work.

 

1E) CREATE SQLITE DATABASE

S1B_create.py
# (A) LOAD PACKAGES
import sqlite3, os
from sqlite3 import Error
 
# (B) DATABASE + SQL FILE
DBFILE = "feedback.db"
SQLFILE = "S1A_feedback.sql"
 
# (C) DELETE OLD DATABASE IF EXIST
if os.path.exists(DBFILE):
  os.remove(DBFILE)
 
# (D) IMPORT SQL
conn = sqlite3.connect(DBFILE)
with open(SQLFILE) as f:
  conn.executescript(f.read())
conn.commit()
conn.close()
print("Database created!")

Well, this should not be a surprise – Just read the above SQL file and create feedback.db.

 

 

STEP 2) FEEDBACK LIBRARY

S2_lib.py
# (A) LOAD SQLITE MODULE
import sqlite3
DBFILE = "feedback.db"

# (B) HELPER - RUN SQL QUERY
def query(sql, data):
  conn = sqlite3.connect(DBFILE)
  cursor = conn.cursor()
  cursor.execute(sql, data)
  conn.commit()
  conn.close()
 
# (C) HELPER - FETCH ALL
def select(sql, data=[]):
  conn = sqlite3.connect(DBFILE)
  cursor = conn.cursor()
  cursor.execute(sql, data)
  results = cursor.fetchall()
  conn.close()
  return results
 
# (D) GET QUESTIONS
def get(id):
  return select("SELECT * FROM `feedback_questions` WHERE `feedback_id`=?", [id])
 
# (E) SAVE USER FEEDBACK
# uid : user id
# fid : feedback id
# feed : array of feedback data
def save(uid, fid, feed):
  sql = "REPLACE INTO `feedback_users` (`user_id`, `feedback_id`, `question_id`, `feedback_value`) VALUES "
  data = []
  for qid, ans in feed.items():
    sql = sql + "(?,?,?,?),"
    data.extend([uid, fid, qid, ans])
  sql = sql[:-1] + ";"
  query(sql, data)
  return True

With the database in place, we now need a library to work with it. This is a simple one to get things started:

  1. Load the SQLite module, and specify the database file.
  2. query() Helper function to run an SQL query.
  3. select() Helper function to run a SELECT query.
  4. get() Get feedback questions for specified feedback ID.
  5. save() Save the given user feedback.

 

STEP 3) FLASK SERVER

3A) INITIALIZE

S3_server.py
# (A) INIT
# (A1) LOAD MODULES
from flask import Flask, render_template, request, make_response
import s3_lib as feedback
 
# (A2) FLASK SETTINGS + INIT
HOST_NAME = "localhost"
HOST_PORT = 80
app = Flask(__name__)
# app.debug = True
 
# (A3) FIXED USER ID & FEEDBACK ID FOR THIS DEMO
uid = 999
fid = 1

Next, we deal with the Flask HTTP server itself.

  • (A1) Self-explanatory. Load all the required Flask modules, and use the library we created in the previous step.
  • (A2) Server settings.
  • (A3) For this example, we will fix the user ID and feedback ID for simplicity.

 

 

3B) HTTP ROUTES

S3_server.py
# (B) FEEDBACK HTML PAGE
@app.route("/")
def index():
  # (B1) GET FEEDBACK QUESTIONS
  questions = feedback.get(fid)
 
  # (B2) RENDER HTML PAGE
  return render_template("S4_feedback.html", qns=questions)
 
# (C) SAVE FEEDBACK FORM
@app.route("/save/", methods=["POST"])
def save():
  feedback.save(uid, fid, request.form)
  return make_response("Saved - Create your own thank you page...", 200)
 
# (D) START
if __name__ == "__main__":
  app.run(HOST_NAME, HOST_PORT)
  • (B) Serve the HTML feedback at the base URL /.
  • (C) Save the submitted feedback form when it is sent to /save/.
  • (D) Captain Obvious. Start the HTTP server.

 

STEP 4) HTML FEEDBACK PAGE

templates/S4_feedback.html
<form method="post" class="feed-form" action="save/" target="_blank">
{% for q in qns %}
  <!-- (A) QUESTION -->
  <div class="feed-qn">{{ q[2] }}</div>
 
  <!-- (B) ANSWER -->
  {% if q[3] == "R" %}
  <div class="feed-r">
    {% for i in range(5) %}
    <input type="radio" name="{{ q[1] }}" value="{{ i+1 }}"{{ " checked" if i==2 else "" }}>
    {% endfor %}
  </div>
  {% else %}
  <input type="text" name="{{ q[1] }}" class="feed-o" required>
  {% endif %}
  {% endfor %}
 
  <!-- (C) SUBMIT -->
  <input type="submit" value="Save" class="feed-go">
</form>

Finally, the HTML page generates feedback forms dynamically.

 

 

DONE!

The end – Submit the form and verify the entry inside the database.

 

EXTRA BITS & LINKS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

OPENING FOR PUBLIC FEEDBACK

Yes, it is possible. But we will have to deal with spam and find alternate ways to track the users.

  • Change user_id to a TEXT field instead.
  • Generate a random unique ID, set it in a cookie.
  • Use the randomly generated ID as the user_id. Once the user has submitted before, don’t allow resubmission.
  • Also, implement reCaptcha to fight off some spam.

This is not perfect, users still can clear their cookies and spam submit the feedback form. But at least it is not as easy with some checks in place.

 

USER-ONLY FEEDBACK

It is highly recommended that you open the feedback system to registered users only. This will ensure data integrity and stop spam significantly. If you do not have a user system… I only have a “simple no database version” at the time of writing – You will have to build your own otherwise.

 

BASIC SYSTEM ONLY!

Before the toxic troll things start to vomit mental diarrhea, this is tutorial is only a first step. It is far from a “complete” and “professional” system.

  • SQLite is convenient and great for studying. But being file-based makes it very limited – Poor overall performance, will not work on cluster and cloud setup. So please pick up a database in your own free time – MySQL, MongoDB, Postgre, etc…
  • No admin panel or user system. I figured some of you guys already have an established system, no point reinventing the wheel.
  • Reports – Do your own.
  • A “nice thank you” page after submission.

There are endless things that can be done to improve this system, but for this tutorial – It works, and we have covered the necessary basics.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

Leave a Comment

Your email address will not be published. Required fields are marked *