In the age of Online Education, online examination is a very essential application of EduTech industry. If you have appeared for some kind of online examination or competitive test, you must be wondering how easy or how difficult it is to make such an app. Well, it is not that difficult. In this post we will make you understand how to create a simple Online Quiz App using Flask and PostgreSQL.
Database Table for Online Quiz App
This is a simple application of the level of a minor project for beginners in Flask. So, only one table is used for storing subject wise questions required for the online quiz. Each question is identified by an ID and subject. The last two field in the table are used to apply color to the button representing the question in dashboard and ‘disabled’ status of the button.
Working of the Application
The index page of the application displays blocks with name of the subjects for which quizzes are available. These blocks get the subject names from questions table. The questions table is used to get the distinct subjects which are then passed to the index page using render_tamplate for displaying the clickable blocks of subjects to be chosen by a user.
After a user selects a subject, she is taken to the dashboard where all the questions of the selected subject are displayed as red buttons with question number in the left panel. The first question is displayed in the right panel with the possible answers as radio buttons and a “Save Answer “ button. A user can select any question represented by red color button.
When a user selects an answer from the options and clicks on the “Save Answer” Button that button on left panel for that question becomes green and is disabled. When the user clicks button ”Display Result” from the left panel, the final screen is displayed with a message displaying correct number of answers. “Go to Home Page” button takes back to index page where a user can attempt another quiz
models.py
import os from flask import Flask from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class questions(db.Model): __tablename__="questions" qid = db.Column(db.Integer, primary_key=True) subject =db.Column(db.String, nullable=False) question =db.Column(db.String, nullable=False) option1 = db.Column(db.String, nullable=True) option2 = db.Column(db.String, nullable=True) option3 = db.Column(db.String, nullable=True) option4 = db.Column(db.String, nullable=True) answer = db.Column(db.Integer, nullable=True) bcol = db.Column(db.String, nullable=True)
layout.html
<!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <script src="/static/jsfile.js"></script> <title>{% block title %}{% endblock %}</title> </head> <body > <div class="container"> <div class="row" style="border-style:solid;padding:20px; text-align: right;"> <b>{% block pagetitle %}{% endblock %}</b> </div> <div class="row" style="border:groove;"> <div class="col-sm-2" style="border-right:groove;"> {% block questList %}{% endblock %} </div> <div class="col-sm" style="margin:10%;"> {% block content %}{% endblock %} </div> </div> <div class="row"> <div id="footer" > Copyright 2020 by CSVeda.com </div> </div> </div> </body> </html>
jsfile.js (save under static folder of the application)
$( document ).ready(function() { $( ".js-click" ).click(function() { $( ".js-click" ).css('background', 'green'); }); });
application.py
from flask import Flask, render_template, jsonify, request,redirect,flash,session from models import * folder_name="static" app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql://postgres:yourpasswrodhere @localhost:5432/OnlineQuiz" app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False app.secret_key = b'hkahs3720/' # use a random string app.config["SESSION_PERMANENT"] = False app.config["SESSION_TYPE"] = "filesystem" db.init_app(app) #to change color of question buttons and disable def setStatus(qlist): qAttempt=[] strval=session['result'].strip() ans=strval.split(',') for i in range(int(len(ans)/2)): qAttempt.append(int(ans[2*i])) for rw in qlist: if rw.qid in qAttempt: rw.bcol='green' # set color rw.status='disabled' # disable @app.route("/") def index(): session['result']="" subList=questions.query.with_entities(questions.subject).distinct() return render_template("index.html",subList=subList) @app.route('/quiz', methods=["POST"]) def quiz(): subject= request.form.get('sub') questList=questions.query.filter_by(subject=subject).all() quest=questions.query.filter_by(subject=subject).first() return render_template("dashboard.html",questList=questList, quest=quest) @app.route("/showQuest/<string:subject>,<int:qid>") def showQuest(subject,qid): questList=questions.query.filter_by(subject=subject).all() quest=questions.query.filter_by(qid=qid).first() setStatus(questList) return render_template("dashboard.html",questList=questList, quest=quest) @app.route('/saveAns',methods=["POST"]) def saveAns(): qid=request.form.get('qid') ans=request.form.get('answer') sub=request.form.get('subject') #update the question id and its selected answer in session variable result res=session['result'] res= res+qid+','+ans+',' session['result']=res questList=questions.query.filter_by(subject=sub).all() setStatus(questList) quest=questions.query.filter_by(qid=qid).first() return render_template("dashboard.html",questList=questList, quest=quest) @app.route("/logout") def logout(): #calculate result count=0 txt="" strval=session['result'].strip() #split result string by ',' ans=strval.split(',') for i in range(int(len(ans)/2)): qd=ans[2*i] # get question id qn=ans[2*i+1] # get the sorresponding answer tt=int(qd) quest=questions.query.filter_by(qid=tt).first() actans=quest.answer if actans==int(qn):#compare correct answer in questions table with answer chosen by user count=count+1 # increment counter txt=txt+'You have '+ str(count)+ ' correct questions out of '+ str(int(len(ans)/2))+ ' questions ' # set the result statement return render_template("result.html",txt=txt)
index.html
{% extends "layout_reg.html" %} {% block title %} The Variety Quiz Portal {% endblock %} {% block pagetitle %} Choose a Subject {% endblock %} {% block body %} <form method="POST" action={{url_for('quiz')}}> {% for sb in subList %} <input type="submit" name="sub" value='{{sb.subject}}' style="height:150px; width:150px;border: 1px solid; word-wrap:normal; margin:10px; padding: 10px; box-shadow: 5px 10px 10px #888888;"> {% endfor %} </form> {% endblock %}
layout_reg.html
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <title>{% block title %}{% endblock %}</title> </head> <body> <div class="container"> <div class="row" style="padding:20px; text-align: right;"> <h4>{% block pagetitle %}{% endblock %}</h4> </div> {% block body %} {% endblock %} </div> </body> </html>
quiz.html
{% block title %} Static Files Example {% endblock %} {% block body %} {% for q in questList %} <a href="{{url_for('quiz',sub=q.subject,qid=q.qid)}}"><button>{{q.qid}}</button></a> {% endfor %} {% endblock %}
Dashboard.html
{% extends "layout.html" %} {% block title %} User Dashboard! {% endblock %} {% block pagetitle %} Quiz for :{{quest.subject}} {% endblock %} {% block questList %} <B> Your Questions</B><br><br> {% for q in questList %} <a href="{{url_for('showQuest',subject=q.subject,qid=q.qid)}}"><button value={{q.qid}} {{q.status}} id={{q.qid}} style="margin:2px; width:40px; height:40px;background-color:{{q.bcol}}" >{{loop.index}}</button></a> {% endfor %} <br><br><a href="{{url_for('logout')}}"><button>Display Result</button></a> {% endblock %} {% block content %} <form method="POST" action={{url_for('saveAns')}}> <div class="question"><h5><input type="text" name="qid" value={{quest.qid}} style="border-style:none; width:20px"> <input type="text" name="subject" value='{{quest.subject}}' style="border-style:none"> </h5></div> <div class="qst">{{quest.question}}</div> <div class="opt"><input type="radio" name="answer" value="1"> {{quest.option1}}</div> <div class="opt"><input type="radio" name="answer" value="2"> {{quest.option2}}</div> <div class="opt"><input type="radio" name="answer" value="3"> {{quest.option3}}</div> <div class="opt"><input type="radio" name="answer" value="4"> {{quest.option4}}</div> <input type="submit" value="Save Answer"/> </form> {% endblock %} <script> function colorbtn(bid) { document.getElementByid(bid).background-color = "green"; } </script>
result.html
{% extends "layout_reg.html" %} {% block title %} Success! {% endblock %} {% block body %} <h1>{{txt}}!</h1> <a href="{{url_for('index')}}"><input type="button" value="Go to home page"></a> {% endblock %}
Possible future enhancements of the App
The Online Quiz App is created in its simplest form. It can be extended by adding following features
- Adding time constraint for each question or online Quiz on the whole
- Making it a User login based application and maintaining the record of users about what quizzes they have attempted along with date of attempt and score.
- The Online Quiz App in this form does not allow modifying answer for an attempted question. It can be enhanced to allow this.
to learn how to create an application using Flask and PostgreSQl click here
layout.html file is missing
Thanks for updating. Added in the post.
Where is the DB file? I am unable to load the index.html
This is the table
CREATE TABLE public.questions
(
qid integer NOT NULL DEFAULT nextval(‘questions_qid_seq’::regclass),
subject character varying(50) COLLATE pg_catalog.”default”,
question character varying(500) COLLATE pg_catalog.”default”,
option1 character varying(50) COLLATE pg_catalog.”default”,
option2 character varying(50) COLLATE pg_catalog.”default”,
option3 character varying(50) COLLATE pg_catalog.”default”,
option4 character varying(50) COLLATE pg_catalog.”default”,
answer smallint,
bcol character varying(10) COLLATE pg_catalog.”default”,
status character varying(15) COLLATE pg_catalog.”default”,
CONSTRAINT questions_pkey PRIMARY KEY (qid)
)
You need to create the index.html code given in the post
Excellent Tutorial, thanks a lot!
Excellent tutorial. Appreciate if you could add the result.html file. Thnks
Thanks Menco. Added the result.html. Please check
Thank you for support.
One additional remark:
Maybe I missed above but index.html and result.html are referring to layout_reg.html:
{% extends “layout_reg.html” %}
I do see above the code for layout.html but not the layout_reg.html .
Thank you for your advise
Its added in the post. Please check now. Thanks for your feedback.
nice tutorial.. But what does the field status do ? What value does it have ?? Please help
It can be used to make a question active or inactive in a quiz. Like, if you don’t want to delete the question from database table but still don’t want it to appear in a quiz. The code right now doesn’t use this field. You can make a separate web page that displays the questions in a table and you can activate/deactivate questions.
im new to flask so can someone tell how i can run this program. would be very helpful
Please refer to https://csveda.com/create-python-website-get-started-with-flask/