From: Richard Mansfield Date: Tue, 5 Aug 2014 22:55:56 +0000 (+1200) Subject: Add option to take a subset of the questions in a quiz X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=c074ff2d45ddba2493116ec04c31e17cbc9e3491;p=django_quiz.git Add option to take a subset of the questions in a quiz Adds a "max_questions" field to a quiz, indicating the number of questions to be answered on each attempt. This is useful when the quiz has a large pool of questions, and students are expected to take multiple attempts and answer a different random subset of questions each time. Each Sitting stores a list of all the questions chosen for the attempt, and the order in which they are presented to the user, so that results can be displayed at the end for the question subset, instead of for the whole quiz. --- diff --git a/quiz/models.py b/quiz/models.py index 86c9ab7..feb16ae 100644 --- a/quiz/models.py +++ b/quiz/models.py @@ -77,6 +77,10 @@ class Quiz(models.Model): "a random order or as they " "are set?") + max_questions = models.PositiveIntegerField(blank=True, null=True, + help_text="Number of questions to be " + "answered on each attempt") + answers_at_end = models.BooleanField(blank=False, default=False, help_text="Correct answer is NOT" @@ -278,12 +282,16 @@ class SittingManager(models.Manager): question_set = quiz.question_set.all() \ .select_subclasses() + if quiz.max_questions and quiz.max_questions < len(question_set): + question_set = question_set[:quiz.max_questions] + questions = "" for question in question_set: questions += str(question.id) + "," new_sitting = self.create(user=user, quiz=quiz, + question_order=questions, question_list=questions, incorrect_questions="", current_score=0, @@ -314,6 +322,9 @@ class Sitting(models.Model): Used to store the progress of logged in users sitting a quiz. Replaces the session system used by anon users. + Question_order is a list of integer pks of all the questions in the + quiz, in order. + Question_list is a list of integers which represent id's of the unanswered questions in csv format. @@ -329,6 +340,8 @@ class Sitting(models.Model): quiz = models.ForeignKey(Quiz) + question_order = models.CommaSeparatedIntegerField(max_length=1024) + question_list = models.CommaSeparatedIntegerField(max_length=1024) incorrect_questions = models.CommaSeparatedIntegerField(max_length=1024, @@ -371,10 +384,13 @@ class Sitting(models.Model): def get_current_score(self): return self.current_score + def _question_ids(self): + return [int(n) for n in self.question_order.split(',') if n] + @property def get_percent_correct(self): dividend = float(self.current_score) - divisor = self.quiz.question_set.all().select_subclasses().count() + divisor = len(self._question_ids()) if divisor < 1: return 0 # prevent divide by zero error @@ -439,14 +455,23 @@ class Sitting(models.Model): self.user_answers = json.dumps(current) self.save() + def get_questions(self): + question_ids = self._question_ids() + return sorted( + self.quiz.question_set.filter(id__in=question_ids).select_subclasses(), + key=lambda q: question_ids.index(q.id)) + @property def questions_with_user_answers(self): output = {} user_answers = json.loads(self.user_answers) - for question in self.quiz.question_set.all().select_subclasses(): + for question in self.get_questions(): output[question] = user_answers[unicode(question.id)] return output + @property + def get_max_score(self): + return len(self._question_ids()) class Question(models.Model): """ diff --git a/quiz/views.py b/quiz/views.py index 66c5125..558f692 100644 --- a/quiz/views.py +++ b/quiz/views.py @@ -197,7 +197,7 @@ class QuizTake(FormView): results = { 'quiz': self.quiz, 'score': self.sitting.get_current_score, - 'max_score': self.quiz.get_max_score, + 'max_score': self.sitting.get_max_score, 'percent': self.sitting.get_percent_correct, 'sitting': self.sitting, 'previous': self.previous, @@ -205,14 +205,14 @@ class QuizTake(FormView): self.sitting.mark_quiz_complete() - if self.quiz.exam_paper is False: - self.sitting.delete() - if self.quiz.answers_at_end: - results['questions'] = self.quiz.get_questions() + results['questions'] = self.sitting.get_questions() results['incorrect_questions'] =\ self.sitting.get_incorrect_questions + if self.quiz.exam_paper is False: + self.sitting.delete() + return render(self.request, 'result.html', results) def anon_load_sitting(self):