Как я могу отображать данные из модели django и сохранять их одновременно, используя представления на основе классов?
Я создаю приложение для викторины, используя Django. Требования следующие:
- Мне нужно сначала отобразить все темы, доступные для викторины, на главной странице.
- При нажатии на определенную страницу нас должно перенаправлять на новую страницу, где мы увидим вопросы.
- Каждый раз должен отображаться один вопрос.
- Кнопка next должна загружать следующий вопрос, и пользователь не может вернуться к предыдущему вопросу.
- После прохождения всех вопросов, пользователь должен быть переведен на другую страницу, на которой отображается результат.
- Для каждого вопроса, который пытаются решить, процесс должен отображаться как 5/10 вопрос, 6/10 вопрос.
- Если пользователь выходит из системы до завершения теста, ему должен быть показан тот же вопрос, когда он войдет в систему.
У меня получается отображать темы .
Проблема в том, что я не могу отобразить один вопрос за раз и сохранить ответ пользователя, используя представление на основе класса. Также я запутался, как мне отобразить прогресс и сохранить запись пользователя, если он/она выходит из системы, не завершив тест, и перенаправить его на следующий вопрос, до которого он пытался ответить.
Я новичок в django и пытаюсь разработать это. Пожалуйста, помогите!
Делюсь своим кодом:
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
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'),
]
Попробуйте с DetailView. Django Docs