How to Create a Quiz Web Application with Python Django
Master Python with 70+ Hands-on Projects and Get Job-ready - Learn Python
Placement-ready Online Courses: Your Passport to Excellence - Start Now
Quiz – best way to check our knowledge on a particular topic.
We have visited a lot of quiz platforms lately, right! Ever wondered if you could develop one.
In this article, we will guide you to develop a quiz application using Python Django. Let’s see what all functionalities we will be developing in this project (for two roles – user and admin):
User:
- Sign up (register)
- Login
- Quiz page (with timer)
- Result page (with score, time taken, percentage score, total questions, correct answers, wrong answers)
Admin:
- Login
- Sign up
- Add Question
- Quiz Page
- Result Page
Project Prerequisites
You should have a basic knowledge of the following technologies:
- HTML: to display content on web page
- CSS: to style HTML document
- JavaScript: to make a timer
- Bootstrap: A front-end framework
- Python: Programming language.
- Django: Python framework
To install Django:
pip install Django
Download Quiz App Python Code
Please download the source code of quiz web application: Quiz Web Application Python Code
Steps to Build Quiz App Project
1. Starting project:
Commands to start the project and app:
django-admin startproject DjangoQuiz cd DjangoQuiz django-admin startapp Quiz
2. Writing Models
Code:
from django.db import models # Create your models here. class QuesModel(models.Model): question = models.CharField(max_length=200,null=True) op1 = models.CharField(max_length=200,null=True) op2 = models.CharField(max_length=200,null=True) op3 = models.CharField(max_length=200,null=True) op4 = models.CharField(max_length=200,null=True) ans = models.CharField(max_length=200,null=True) def __str__(self): return self.question
We just need one model for this project, QuesModel.
Attributes of QuesModels:
- question: This stores the question, we have also defined maximum length of the question i.e. 200
- op1: As the quiz contains Multiple choice questions. This stores option 1 value.
- op2: option2
- op3: option3
- op4: option4
- ans: This indicates which among the four options is the correct ans.
The __str__() method returns a string representation of any object of QuesModel.
In Django when we use Sqlite3 database, we don’t have to write table definitions we just have to write models and after that, we have to run the following commands
Py manage.py makemigrations Py manage.py migrate
3. forms.py
Code:
from django.forms import ModelForm from .models import * from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User class createuserform(UserCreationForm): class Meta: model=User fields=['username','password'] class addQuestionform(ModelForm): class Meta: model=QuesModel fields="__all__"
To access, update, create or delete entries in the database (to implement CRUD functionality), we need forms.
Form makes it easy to implement CRUD functionality as we neither have to create forms to accept information from users nor we have to validate information manually, we can just use is_valid() method to validate the information before updating it in the database.
4. admin.py
Code:
from django.contrib import admin from .models import * # Register your models here. admin.site.register(QuesModel)
Here, we are registering our model to the admin site, so that we can update or access the database from the admin panel also. But we need a superuser to access the admin site.
To create a staff (admin) user, run the below command
py manage.py createsuperuser
5. settings.py
To use javascript we have to specify the path of static files. Therefore, add the following code in settings.py
STATIC_URL = '/static/' STATICFILES_DIRS=[BASE_DIR/'static']
6. urls.py
In this file we are just defining urls. To define urls:
- import view functions: from Quiz.views import *
- add url to urlpatterns: path(‘login/’, loginPage,name=’login’),
Code:
"""DjangoQuiz URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.1/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path from Quiz.views import * from django.conf import settings from django.conf.urls.static import static urlpatterns = [ path('admin/', admin.site.urls), path('', home,name='home'), path('addQuestion/', addQuestion,name='addQuestion'), path('login/', loginPage,name='login'), path('logout/', logoutPage,name='logout'), path('register/', registerPage,name='register'), ] urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
7. views.py :
Code:
from django.shortcuts import redirect,render from django.contrib.auth import login,logout,authenticate from .forms import * from .models import * from django.http import HttpResponse # Create your views here. def home(request): if request.method == 'POST': print(request.POST) questions=QuesModel.objects.all() score=0 wrong=0 correct=0 total=0 for q in questions: total+=1 print(request.POST.get(q.question)) print(q.ans) print() if q.ans == request.POST.get(q.question): score+=10 correct+=1 else: wrong+=1 percent = score/(total*10) *100 context = { 'score':score, 'time': request.POST.get('timer'), 'correct':correct, 'wrong':wrong, 'percent':percent, 'total':total } return render(request,'Quiz/result.html',context) else: questions=QuesModel.objects.all() context = { 'questions':questions } return render(request,'Quiz/home.html',context) def addQuestion(request): if request.user.is_staff: form=addQuestionform() if(request.method=='POST'): form=addQuestionform(request.POST) if(form.is_valid()): form.save() return redirect('/') context={'form':form} return render(request,'Quiz/addQuestion.html',context) else: return redirect('home') def registerPage(request): if request.user.is_authenticated: return redirect('home') else: form = createuserform() if request.method=='POST': form = createuserform(request.POST) if form.is_valid() : user=form.save() return redirect('login') context={ 'form':form, } return render(request,'Quiz/register.html',context) def loginPage(request): if request.user.is_authenticated: return redirect('home') else: if request.method=="POST": username=request.POST.get('username') password=request.POST.get('password') user=authenticate(request,username=username,password=password) if user is not None: login(request,user) return redirect('/') context={} return render(request,'Quiz/login.html',context) def logoutPage(request): logout(request) return redirect('/')
View.py is the file which contains the main or we can say the business logic of the project as this file can only access the database and also it can pass the information to templates so that it can be displayed on the web browser.
Home
This is the most important view of our project as this method is responsible for displaying the quiz page as well as the result page.
For Quiz Page: It renders all the questions from QuesModel and then it just passes all the questions to home.html
For result page: It calculates the score by giving ten marks for every correct question and zero (i.e. no negative marking) for every incorrect question. And then it calculates the percentage score.
Finally, it sends all these calculated values along with time elapsed, number of correct answers, number of incorrect answers to result.html. Result.html displays all this information.
Add Question:
This method is only for admin, if any user tries to access this method, the user is redirected to the home page. We are basically using the add question form in this to create a form object.
To validate the information entered by the user we are using is_valid method and after validating the information we are adding another question in the database using save() method.
Result.html
{% extends 'Quiz/dependencies.html' %} {% block content %} <div class="container "> <div class="card-columns" style="padding: 10px; margin: 20px;"> <div class="card" align="centre " style="width: 32rem; border:5px black solid"> <img class="card-img-top" src="http://kmit.in/emagazine/wp-content/uploads/2018/02/karnataka-results.jpg" alt="Card image cap"> <div class="card-body"> <h5 class="card-title">Score: {{score}}</h5> <p class="card-text">Percentage: {{percent}}%</p> <p class="card-text">Time Taken: {{time}} seconds</p> <p class="card-text">Correct answers: {{correct}}</p> <p class="card-text">Incorrect answers: {{wrong}}</p> <p class="card-text">Total questions: {{total}}</p> <h5>All the best for next quiz!</h5> </div> </div> </div> </div> {% endblock %}
Result page:
Home.html
{% extends 'Quiz/dependencies.html' %} {% block content %} {% load static %} <div class="container "> <h1>Welcome to DataFlair Quiz</h1> <div align="right " id="displaytimer"><b>Timer: 0 seconds</b></div> <form method='post' action=''> {% csrf_token %} {% for q in questions%} <div class="form-group"> <label for="question">{{q.question}}</label> </div> <div class="form-check"> <div class="form-check"> <input class="form-check-input" type="radio" name="{{q.question}}" id="gridRadios1" value="option1" checked> <label class="form-check-label" for="gridRadios1"> {{q.op1}} </label> </div> <div class="form-check"> <input class="form-check-input" type="radio" name="{{q.question}}" id="gridRadios2" value="option2"> <label class="form-check-label" for="gridRadios2"> {{q.op2}} </label> </div> <div class="form-check"> <input class="form-check-input" type="radio" name="{{q.question}}" id="gridRadios1" value="option3"> <label class="form-check-label" for="gridRadios1"> {{q.op3}} </label> </div> <div class="form-check"> <input class="form-check-input" type="radio" name="{{q.question}}" id="gridRadios2" value="option4"> <label class="form-check-label" for="gridRadios2"> {{q.op4}} </label> </div> <br> </div> {% endfor %} <input id='timer' type='hidden' name="timer" value=""> <br> <button type="submit" class="btn btn-primary">Submit</button> </form> {% block script %} <script> console.log('hello world') const timer=document.getElementById('displaytimer') console.log(timer.textContent) const inputtag = document.getElementById('timer') t=0 setInterval(()=>{ t+=1 timer.innerHTML ="<b>Timer: " +t+" seconds</b>" inputtag.value = t },1000) </script> {% endblock script %} </div> {% endblock %}
Quiz page
For admin, only the navigation bar is different, it has one button for adding questions.
Navbar.html
{% load static %} <style> .greet{ font-size: 18px; color: #fff; margin-right: 20px; } </style> <nav class="navbar navbar-expand-lg navbar-dark bg-dark"> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item active"> <a class="nav-link" href="{% url 'home' %}">Home</a> </li> </li> <li class="nav-item active"> {% if request.user.is_staff %} </li> <li class="nav-item active"> <a class="nav-link" href="{% url 'addQuestion' %}">Add Question</a> </li> {% endif %} </li> <li class="nav-item"> <a class="nav-link" href="{% url 'login' %}">Login</a> </li> </ul> </div> <span class="greet">Hello, {{request.user}}</span> <span ><a class="greet" href="{% url 'logout' %}">Logout</a></span> </nav>
AddQuestion.html
{% extends 'Quiz/dependencies.html' %} {% block content %} <div class="jumbotron container row"> <div class="col-md-6"> <h1>Add Question</h1> <div class="card card-body"> <form action="" method="POST"> {% csrf_token %} {{form.as_p}} <br> <input type="submit" name="Submit"> </form> </div> </div> </div> </div> {% endblock %}
Add Question page
dependencies.html
{% load static %} <html> <head> <title> DataFlair Online Quiz with Django </title> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> </head> <body> {% include 'Quiz/navbar.html' %} {% block content %} {% endblock %} <br> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script> </body> </html>
Login.html
{% extends 'Quiz/dependencies.html' %} {% load static%} {% block content %} <div class="container jumbotron"> <form method="POST" action=""> {% csrf_token %} <p><input type="text" name="username" placeholder="Username..."></p> <p><input type="password" name="password" placeholder="Password..." ></p> <input class="btn btn-success" type="submit" value="Login"> <p>Do not have an account<a href='{% url 'register' %}'>Register</a></p> </form> </div> {% endblock %}
Register.html
{% extends 'Quiz/dependencies.html' %} {% load static %} {% block content %} <div class="container jumbotron"> <form method="POST" action="" > {% csrf_token %} {{form.as_p}} <input class="btn btn-success" type="submit" value="Register Account"> </form> </div> {% endblock %}
Summary
We have developed an Online Quiz application Project using Python Django. We developed quiz web application with following functionalities: Login, Sign up, Add Question, Quiz Page, Result Page. You can develop more interesting projects with Django, so keep exploring and keep learning.
If you are Happy with DataFlair, do not forget to make us happy with your positive feedback on Google
What is username and password
you can create superuser and go own
It doesn’t work. When the correct answer is chosen, it chooses it as wrong. Nothing is ever correct, always wrong and I am using exactly the code here….
Now I am thinking, is it because of the part that said:
if q.ans == request.POST.get(q.question):
…….
Because q.ans may never be equal to q.question which is the question asked. Now I changed it to :
if q.ans == q.op1 or q.op2 or q.op3 or q.op4:
……….
Everything was showing as correct answer on the result, whether i chose the right answer or not….What am i getting wrong? Help, i am new to django
How can I login as admin
Hey Ferdinand,
This is what I did. I downloaded the zip file, unzip the file (I moved the zip file on Documents and extract it there). Then I went to the directory where manage.py is located via terminal, and ran “python manage.py runserver”.
Everything works fine.
This worked for me, thanks
It’s not working for me, manage.py file/directory does not exist is showing
while creating the question give as optionn (i.e): option1 in the answer field. Everthing works fine otherwise
While creating the question give as optionn (i.e): option1 in the answer field. Everthing works fine otherwise.
where i can download zip file
where i can download zip file
That’s right. It never captures the user’s answer, it only captures the option number but never the value inside it. So, to compare actual answer we do not have the real value from the user. If anyone has found out how to get the value please comment.
Use this and it should work.
# Create your views here.
def home(request):
if request.method == ‘POST’:
questions=QuesModel.objects.all()
score=0
wrong=0
correct=0
total=0
for q in questions:
total+=1
answer = request.POST.get(q.question) # Gets user’s choice, i.e the key of answer
items = vars(q) # Holds the value for choice
print(items[answer])
# Compares actual answer with user’s choice
if q.ans == items[answer]:
score+=10
correct+=1
else:
wrong+=1
percent = score/(total*10) *100
context = {
‘score’:score,
‘time’: request.POST.get(‘timer’),
‘correct’:correct,
‘wrong’:wrong,
‘percent’:percent,
‘total’:total
}
return render(request,’mcqapp/result.html’,context)
else:
questions=QuesModel.objects.all()
context = {
‘questions’:questions
}
return render(request,’mcqapp/home.html’,context)
def home(request):
if request.method == ‘POST’:
questions=QuesModel.objects.all()
score=0
wrong=0
correct=0
total=0
for q in questions:
total+=1
answer = request.POST.get(q.question) # Gets user’s choice, i.e the key of answer
items = vars(q) # Holds the value for choice
print(items[answer])
# Compares actual answer with user’s choice
if q.ans == items[answer]:
score+=10
correct+=1
else:
wrong+=1
percent = score/(total*10) *100
context = {
‘score’:score,
‘time’: request.POST.get(‘timer’),
‘correct’:correct,
‘wrong’:wrong,
‘percent’:percent,
‘total’:total
}
return render(request,’mcqapp/result.html’,context)
else:
questions=QuesModel.objects.all()
context = {
‘questions’:questions
}
return render(request,’mcqapp/home.html’,context)
bro now this code is working properly?
bro alredy you faced this poblem if you know this one,
please help to all ,
keep the correct code
Just change the value of the Radio Button in the Html file…….It should work
bro reply
bro reply
how to go to admin? /admin page where super user can login?
To avoid issues with the answer just enter option+number eg option1 instead of the the answer in the ans box when adding the question.
The problem is that the answers are hard coded in the home.html file:
value=”option1″
This needs to be:
value=”{{q.op1}}”
How to delete a question
Any way to upload Questions that has images in them as well. For Example:
String + img.png / jpg / tiff + string or:
String
\n mpg.png / jpg / tiff
Can some one help ,How to run it .
pip3 install gunicorn
gunicorn DjangoQuiz.wsgi:application –bind 0.0.0.0:8000
this is very great coding , but even when the right answers are choosen it is displaying wrong , kindly help with that soon pls
thank you
it shows many errors after executing it
there is error regarding static files you should provide js,css files code also
how would you approach this for a bank of 400 questions ?