]> git.parisson.com Git - django_quiz.git/commitdiff
Add option to take a subset of the questions in a quiz
authorRichard Mansfield <richard@dragonfly.co.nz>
Tue, 5 Aug 2014 22:55:56 +0000 (10:55 +1200)
committerRichard Mansfield <richard@dragonfly.co.nz>
Tue, 5 Aug 2014 23:24:49 +0000 (11:24 +1200)
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.

quiz/models.py
quiz/views.py

index 86c9ab7379fb565014dff66f476b55d867b36daa..feb16ae77e78830256af50bc155f161672add59a 100644 (file)
@@ -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):
     """
index 66c512570c1230f43474be493e528a13f7762280..558f692c8228723a99829ab85655f8fe3e7cc8da 100644 (file)
@@ -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):