This will be a lengthy post, please have patience with me, I just started with Django and try to wrap my head around it. I created a site that will go thru exam questions one at a time, displaying the question and the multiple choice answers like on countless other websites. The challenge I experience is when the user clicks "NEXT" on the pagination buttons, I would like for the selected answer(option) to be saved back to the database. I tried it with AJAX scripts but the view never got executed. Maybe there is a better way to do this or could you please point me into the right direction? I will post all of my code and hope someone can please assist me. Thank you for taking the time to look at this.
I start with the models.py:
from django.db import models
class QuesModel(models.Model):
question = models.TextField(null=True)
code_snippet = models.TextField(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
class Answer(models.Model):
ans_id = models.AutoField(primary_key=True)
question_id = models.ForeignKey(QuesModel, on_delete=models.CASCADE)
fname = models.CharField(max_length=50)
lname = models.CharField(max_length=50)
examdate = models.DateField(auto_now_add =True)
answer = models.PositiveSmallIntegerField()
def __int__(self):
return QuesModel.question[self.question_id]
template is home.html:
{% extends 'Quiz/dependencies.html' %}
{% block content %}
{% load static %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="container">
<h1>Welcome to my Quiz</h1>
{% for q in page_obj %}
<form method="post" action="{% url 'submit_answers' %}">
{% csrf_token %}
<input type="hidden" name="question_id" value="{{ q.id }}">
<!-- <input type="hidden" name="answer" value="{{ answer }}"> -->
<input type="hidden" name="date" value="{{ default_date }}">
<div class="form-group">
<div class="card text-bg-light mb-0" style="max-width: 50rem;">
<div class="card-header">
<code>
Question {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}<br>
{{q.question}}
</code>
</div>
<div class="card-body">
<class="card-text">
<label for="question">
<pre class="python"><code>{{q.code_snippet|linebreaks|escape}}</code></pre>
</label>
</div>
</div>
<br>
<div class="form-check">
<input class="form-check-input" type="radio" name="{{ q.question }}" id="option1" value="1" data-question-id="{{ q.id }} required>
<label class="form-check-label" for="option1">
{{ q.op1 }}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="{{ q.question }}" id="option2" value="2" data-question-id="{{ q.id }} required>
<label class="form-check-label" for="option2">
{{ q.op2 }}
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="{{q.question}}" id="gridRadios1" data-question-id="{{ q.id }} value="3">
<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" data-question-id="{{ q.id }} value="4">
<label class="form-check-label" for="gridRadios2">
{{q.op4}}
</label>
</div>
<br>
</div>
</div>
</div>
</div>
{% endfor %}
<div class="container">
<nav aria-label="Page navigation example">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a>
</li>
{% endif %}
<li class="page-item disabled">
<a class="page-link" tabindex="-1" aria-disabled="true">Question {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</a>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="{% url 'home' %}?page={{ page_obj.next_page_number }}" >Next</a>
</li>
{% endif %}
</ul>
</nav>
</div>
<div class="container">
<input id='timer' type='hidden' name="timer" value="">
<br>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
{% block script %}
<script>
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 %}
Last is the views.py:
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
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
import datetime
def home(request):
print("HOMEVIEW")
print("REQUEST METHOD=" + request.method) # Debugging line
print("POST=")
print(request.POST) # Debugging line
# Render the question page
if request.method == 'POST':
print("IN POST")
questions=QuesModel.objects.all()
paginator = Paginator(questions, 1)
page_number = request.GET.get('page')
try:
page_obj = paginator.page(page_number)
except PageNotAnInteger:
# If the page is not an integer, show the first page of results
page_obj = paginator.page(1)
except EmptyPage:
# If the page is out of range, show the last page of results
page_obj = paginator.page(paginator.num_pages)
context = {
'page_obj': page_obj,
'answer': request.POST.get('answer'), # define and pass answer to template
}
return render(request,'Quiz/home.html',context)
def save_answer(request):
print("XXXXXXX")
print(request.method) # Debugging line
print(request.POST) # Debugging line
if request.method == 'POST':
# answer = request.POST['answer']
# question_id = request.POST['question_id']
# # Save the answer to the database
# answer = Answer(question_id=question_id, examdate=default_date, answer=answer)
# answer.save()
return HttpResponse('Success')
#Return an error response if the request method is not 'POST'
return HttpResponse('Error: Invalid request method')
def submit_answers(request):
print("submit_answers")
if request.method == 'POST':
print(request.POST)
questions=QuesModel.objects.all()
score=0
wrong=0
correct=0
total=0
incorrect_answers = []
for q in questions:
items = {'op1': q.op1, 'op2': q.op2, 'op3': q.op3, 'op4': q.op4}
total+=1
answer = request.POST.get(q.question) # Gets user’s choice, i.e the key of answer
print(request.POST.get(q.question))
print(q.ans)
print()
if q.ans == request.POST.get(q.question):
score+=10
correct+=1
else:
if q.ans != request.POST.get(q.question):
wrong += 1
testvar=request.POST.get(q.question)
incorrect_answers.append({'question': q.question, 'correct_answer': q.ans, 'user_answer': request.POST.get(q.question) } )
percent = score/(total*10) *100
context = {
'score':score,
'time': request.POST.get('timer'),
'correct':correct,
'wrong':wrong,
'percent':percent,
'total':total,
'incorrect_answers': incorrect_answers, # pass list to template
}
return render(request,'Quiz/result.html',context)
def default_date():
return datetime.datetime.now()
def pageme(request):
print("pageme_here")
questions = QuesModel.objects.all()
paginator = Paginator(questions, 1)
page_number = request.GET.get('page')
try:
page_obj = paginator.page(page_number)
except PageNotAnInteger:
page_obj = paginator.page(1)
except EmptyPage:
page_obj = paginator.page(paginator.num_pages)
context = {
'page_obj': page_obj,
}
return render(request, 'Quiz/pageme.html', context)
def saveme(request):
# Perform some actions here, such as saving data to the database
print("saveme_here") # Debug statement
return HttpResponse("Save successful") # Return a response to the client
# def save_answer(request):
# if request.method == 'POST':
# answer = request.POST['answer']
# question_id = request.POST['question_id']
# # Save the answer to the database
# answer = Answer(question_id=question_id, examdate=default_date, answer=answer)
# answer.save()
# return HttpResponse('Success')
# return HttpResponse('Error')
# def home(request):
# if request.method == 'POST':
# print(request.POST)
# questions=QuesModel.objects.all()
# #answer
# answer = request.POST.get('answer')
# question_id = request.POST.get('question_id')
# examdate = request.POST.get('date')
# answer = Answer(question_id=question_id, examdate=examdate, answer=answer)
# answer.save()
# #end answer
# score=0
# wrong=0
# correct=0
# total=0
# incorrect_answers = []
# for q in questions:
# items = {'op1': q.op1, 'op2': q.op2, 'op3': q.op3, 'op4': q.op4}
# total+=1
# answer = request.POST.get(q.question) # Gets user’s choice, i.e the key of answer
# print(request.POST.get(q.question))
# print(q.ans)
# print()
# if q.ans == request.POST.get(q.question):
# score+=10
# correct+=1
# else:
# if q.ans != request.POST.get(q.question):
# wrong += 1
# testvar=request.POST.get(q.question)
# incorrect_answers.append({'question': q.question, 'correct_answer': q.ans, 'user_answer': request.POST.get(q.question) } )
# percent = score/(total*10) *100
# context = {
# 'score':score,
# 'time': request.POST.get('timer'),
# 'correct':correct,
# 'wrong':wrong,
# 'percent':percent,
# 'total':total,
# 'incorrect_answers': incorrect_answers, # pass list to template
# }
# return render(request,'Quiz/result.html',context)
# else:
# questions=QuesModel.objects.all()
# paginator = Paginator(questions, 1)
# page_number = request.GET.get('page')
# try:
# page_obj = paginator.page(page_number)
# except PageNotAnInteger:
# page_obj = paginator.page(1)
# except EmptyPage:
# page_obj = paginator.page(paginator.num_pages)
# context = {
# 'page_obj': page_obj,
# }
# 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('/')
Please excuse this messy code, I tried all kinds of things and now I hope I can finish it with your help.
Here, I have tried to change your code and made some changes.
models.py
Note: Django provides a default "id" field for each model so no need for ans_id and in the Answer model 'question' field is updated with alias 'ques'
Then go to your command line and execute commands
Add some questions and answers
views.py
Note: Be careful while copying the code ... it may give Indentation error so check that as well
Now just replace your home template with this home.html (here, I didn't have any idea of 'dependencies.html' so I haven't extended that so I have created home.html and results.html )
add below two templates in folder "Quiz". Quiz will have this templates
home.html
Next step, Add results.html to quiz
results.html
Note: : Here you can customize above template...I kept it simple and focused on your problem statement
Final step is route urls,
urls.py
This all took my day so please verify and let me know whether this solves your problem or not...
Thank You