'How can I display data from django model and save at the same time using class based views?
I am creating a quiz app using Django. The requirements are:
- I need to first display all the topics available for the quiz on the homepage.
- Clicking on a particular page should redirect us to a new page where we will see the questions.
- Each time one question should be displayed.
- The next button should load the next question and the user cant go back to the previous question.
- After attempting all the questions, the user should be taken to another page that displays the score.
- For each question being attempted, the process should be displayed like 5/10 question, 6/10 question.
- If a user logs out before completing the quiz, he/she must be displayed the same question once he logs in.
I am able to display the topics .
The problem is I am not able to display one question at a time and store the user's answer using the class based view. Also I am confused how will I display progress and store the user record if he/she logs out without completing the quiz and redirect them to the very next question till where they had attempted.
I am new to django and trying to develop this. Please HELP!
Sharing my code:
Models.py
from django.db import models
from django.contrib.auth.models import User
import uuid
class Topic(models.Model):
t_id = models.UUIDField(
primary_key = True,
default = uuid.uuid4,
editable = False)
topic = models.CharField(max_length=200)
time_required = models.IntegerField(help_text="Duration of Quizz in minutes")
def __str__(self):
return f"{self.topic}"
class Question(models.Model):
q_id = models.UUIDField(
primary_key = True,
default = uuid.uuid4,
editable = False)
question = models.CharField(max_length=200)
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
def __str__(self):
return self.question
class Answer(models.Model):
a_id = models.UUIDField(
primary_key = True,
default = uuid.uuid4,
editable = False)
answer= models.CharField(max_length=100)
is_correct=models.BooleanField(default=False)
question=models.ForeignKey(Question, on_delete=models.CASCADE)
def __str__(self):
return f"{self.answer}"
class UserRecord(models.Model):
User=models.ForeignKey(User, on_delete=models.CASCADE)
question=models.CharField(max_length=100)
answer_choosen=models.CharField(max_length=100)
def __str__(self):
return f"{self.User} | {self.question} | {self.answer_choosen}"
views.py
from django.views.generic import ListView
from django.contrib.auth.decorators import login_required
from .models import Topic, Question, Answer, UserRecord
from django.utils.decorators import method_decorator
from django.shortcuts import render,redirect
@method_decorator(login_required, name='dispatch')
class TopicView(ListView):
model = Topic
template_name = 'quiz/topic.html'
context_object_name = 'topics'
def nextques(request,t_id):
questions=Question.objects.filter(topic=t_id)
total_questions=[]
for question in questions:
total_questions.append(str(question.q_id))
user_answered=UserRecord.objects.filter(User=request.user)
answered_list=[]
for answered_question in user_answered:
answered_list.append(str(answered_question.question))
for question_id in total_questions:
if question_id not in answered_list:
questionset=Question.objects.filter(q_id=question_id)
answerset=Answer.objects.filter(question=question_id)
break
else:
continue
context={
"questions":questionset,
"answers":answerset,
}
if request.method=="POST":
user=request.user
question_id=request.POST.get('hidden1')
question=request.POST.get('hidden')
answer_id=request.POST.get(question)
query=UserRecord(User=user,question=question_id,answer_choosen=answer_id)
query.save()
if len(user_answered)<len(total_questions):
return render(request, "quiz/quizz.html", context=context)
else:
return render(request, "quiz/quizend.html")
base.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="{% static 'quiz/main.css' %}">
{% block scripts %}
{% endblock scripts %}
<title>Quiz App | {% block title %}{% endblock title %}</title>
</head>
<body>
<header class="site-header">
<nav class="navbar navbar-expand-md navbar-dark bg-steel fixed-top">
<div class="container">
<a class="navbar-brand mr-4" href="#">Quiz App</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggle"
aria-controls="navbarToggle" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarToggle">
<div class="navbar-nav mr-auto">
<a class="nav-item nav-link" href="{% url 'topic' %}">Home</a>
</div>
<!-- Navbar Right Side -->
<div class="collapse navbar-collapse justify-content-end" id="navbarCollapse">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="#">Profile</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'logout' %}">Logout</a>
</li>
</ul>
</div>
</div>
</div>
</nav>
</header>
<div class="row">
<div class="col-md-8">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% block content %}{% endblock %}
</div>
</div>
<footer class="text-center text-white fixed-bottom" style="background-color: #f1f1f1;">
<div class="text-center text-dark p-3" style="background-color: rgba(0, 0, 0, 0.2);">
© 2022:QuizApp
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
</body>
topic.html
{% extends "quiz/base.html" %}
{% load static %}
{% block title %}
Quiz
{% endblock %}
{% block scripts %}
<script src="{% static 'quiz/topic.js' %}" defer></script>
{% endblock scripts %}
{% block content %}
<div class="modal fade" id="quizModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">Start Quiz ?</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body" id="modalbody">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-bs-dismiss="modal">No</button>
<button id="start-button" type="button" class="btn btn-success">Yes, Start</button>
</div>
</div>
</div>
</div>
<div class="container mr-4">
<div class="h1">Topics</div>
<hr />
{% for obj in topics %}
<button class="btn btn-secondary modal-button"
data-bs-pk="{{obj.t_id}}"
data-bs-topic="{{obj.topic}}"
data-bs-time="{{obj.time_required}}"
data-bs-toggle="modal"
data-bs-target="#quizModal">
{{obj.topic}}
</button><br /><br />
{% endfor %}
</div>
{% endblock %}
topic.js
const modalBtns = [...document.getElementsByClassName('modal-button')]
const modalBody = document.getElementById('modalbody')
const startBtn = document.getElementById('start-button')
const url = window.location.href
modalBtns.forEach(modalBtn=> modalBtn.addEventListener('click', ()=>{
const id = modalBtn.getAttribute('data-bs-pk')
const topic = modalBtn.getAttribute('data-bs-topic')
const time = modalBtn.getAttribute('data-bs-time')
modalBody.innerHTML = `
<div class="h5 mb-3">Are you sure you want to begin "<b>${topic}</b>"?</div>
<div class="text-muted">
Time: <b>${time} mins</b>
</div>
`
startBtn.addEventListener('click', ()=>{
window.location.href = url + id
})
}))
quizend.html
{% extends "quiz/base.html" %}
{% block content %}
<h1>This is QuizEnd</h1>
{% endblock content %}
quiz.html
{% extends "quiz/base.html" %}
{% load static %}
{% block title %}
{% endblock title %}
{% block scripts %}
<script>
const url=window.location.href
</script>
{% endblock scripts %}
{% block content %}
<div class="container">
<form id="quiz-form" action="" method="POST" class="mt-3 mb-3">
{% csrf_token %}
<div id="quiz-box">
{% for question in questions %}
{{question}}<br />
{% for answer in answers %}
<div class="form-check">
<input type="hidden" name="hidden1" value="{{question.q_id}}">
<input type="hidden" name="hidden" value="{{question}}">
<input type="radio" class="ans" id="{{question}}-{{answer}}" name="{{question}}" value="{{answer.a_id}}" required>
<label for="{{question}}">{{answer}}</label>
</div>
{% endfor %}<br />
{% endfor %}
<br />
</div>
<button type="submit" class="btn btn-primary mt-3">Next</button>
</form>
</div>
{% endblock content %}
quiz/urls.py
from django.urls import path
from .import views
from .views import TopicView #QuestionListView,
urlpatterns = [
path('', TopicView.as_view(), name='topic'),
path('<t_id>', views.nextques, name='quiz'),
]
urls.py
"""quiz_proj URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/4.0/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 users import views as user_views
from django.contrib.auth import views as auth_views
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('quiz.urls')),
path('register/', user_views.register, name= 'register'),
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name = 'login'),
path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name = 'logout'),
]
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|