Спасибо за ответы. Переход с вопроса на вопрос осуществил с помощью метода модели get_next_question, а результаты по совету Origin храню в сессии, а потом в промежуточную таблицу пишу. Получилось такое:
models.py
class Quiz(models.Model):
class Meta:
...
title = models.CharField(_('Quiz title'), max_length=100, unique=True)
slug = models.SlugField(_('Slug'))
author = models.ForeignKey(User, related_name='author', on_delete=models.CASCADE)
description = models.TextField(_('Quiz description'), blank=True, null=True)
created = models.DateTimeField(_('Created'), auto_now_add=True)
category = models.ManyToManyField(Category, related_name='category', blank=True)
# Выбирает следующий pk вопроса
def get_next_question(self, quiz_slug, question_pk):
questions_pk = []
for q in Quiz.objects.get(slug=quiz_slug).quiz.all():
questions_pk.append(q.pk)
try:
next = questions_pk[questions_pk.index(question_pk)+1]
except IndexError:
next = "DONE"
return next
# Проверяет выбранные ответы
def check_correct_answers(self, queryset, question_pk):
correct = Answer.objects.filter(question=question_pk).filter(correct_answer=True)
return list(correct) == list(queryset)
forms.py
class AnswerForm(forms.ModelForm):
class Meta:
...
def __init__(self, question_pk, *args, **kwargs):
self.question_id = question_pk
super(AnswerForm, self).__init__(*args, **kwargs)
self.fields['answer'] = forms.ModelMultipleChoiceField(queryset=Answer.objects.filter(question=self.question_id), widget=forms.CheckboxSelectMultiple)
views.py
class QuizQuestion(FormView):
model = Quiz
template_name = 'quiz/test.html'
slug_field = 'slug'
form_class = AnswerForm
def form_valid(self, form):
now_quiz = self.kwargs['slug']
session = self.request.session
if not now_quiz in session:
session[now_quiz] = 0
if Quiz.check_correct_answers(self, form.cleaned_data['answer'], self.kwargs['q_pk']):
session[now_quiz] += 1
return super(QuizQuestion, self).form_valid(form)
def get_form_kwargs(self):
kwargs = super(QuizQuestion, self).get_form_kwargs()
kwargs['question_pk'] = self.kwargs['q_pk']
return kwargs
def get_context_data(self, *args, **kwargs):
ctx = super(QuizQuestion, self).get_context_data(*args, **kwargs)
ctx['quiz'] = Quiz.objects.get(slug=self.kwargs['slug'])
ctx['question'] = Question.objects.get(pk=self.kwargs['q_pk'])
return ctx
def get_success_url(self, **kwargs):
next_question = Quiz.get_next_question(self, self.kwargs['slug'], self.kwargs['q_pk'])
if next_question != 'DONE':
return reverse_lazy('quiz:quiz-process', kwargs={'cat_slug': self.kwargs['cat_slug'], 'slug': self.kwargs['slug'], 'q_pk': next_question})
else:
self.save_score()
return reverse_lazy('quiz:quiz')
def save_score(self):
quiz = Quiz.objects.get(slug=self.kwargs['slug'])
correct_answers = self.request.session[self.kwargs['slug']]
if self.request.user.is_authenticated:
user = User.objects.get(username=self.request.user)
try:
s = Score.objects.get(student=user, quiz=quiz)
s.correct_answers = correct_answers
except DoesNotExist:
s = Score(student=user, quiz=quiz, correct_answers=correct_answers)
s.save()
self.request.session.pop(quiz.slug, None)
Вопрос. А как лучше ограничить запись в сессию при открытых нескольких вкладках браузера под одной учетной записью? Получается результат суммируется с нескольких вкладок и может получиться так, что правильных ответов будет больше чем вообще вопросов :)
Пока у меня только идея добавить ключу словаря сессий, который отвечает за подсчет правильных ответов, какой-нибудь идентификатор "вкладки"
Updated 6 Feb. 2018, 18:38 by Igor6556.