diff options
author | Prabhu Ramachandran | 2017-10-07 10:54:39 +0530 |
---|---|---|
committer | GitHub | 2017-10-07 10:54:39 +0530 |
commit | 39ec0271244826b2693f01f6daaa99525404e15a (patch) | |
tree | 04cf534ac2cdc90f386e051588bf443fc61219ff | |
parent | a626f3792d03ccd96a1c49c7096076950d020c5a (diff) | |
parent | 2eb511847777e4e941ed5fc40783086d5e0bdfcc (diff) | |
download | online_test-39ec0271244826b2693f01f6daaa99525404e15a.tar.gz online_test-39ec0271244826b2693f01f6daaa99525404e15a.tar.bz2 online_test-39ec0271244826b2693f01f6daaa99525404e15a.zip |
Merge pull request #343 from adityacp/fix_shuffle_questions
Fix shuffle questions
-rw-r--r-- | yaksh/models.py | 79 | ||||
-rw-r--r-- | yaksh/templates/exam.html | 2 | ||||
-rw-r--r-- | yaksh/test_models.py | 25 | ||||
-rw-r--r-- | yaksh/test_views.py | 6 | ||||
-rw-r--r-- | yaksh/views.py | 3 |
5 files changed, 90 insertions, 25 deletions
diff --git a/yaksh/models.py b/yaksh/models.py index 4859d3e..eb14e06 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals from datetime import datetime, timedelta import json +import random import ruamel.yaml from ruamel.yaml.scalarstring import PreservedScalarString from ruamel.yaml.comments import CommentedMap @@ -851,7 +852,11 @@ class QuestionPaper(models.Model): questions = self.get_ordered_questions() for question_set in self.random_questions.all(): questions += question_set.get_random_questions() - return questions + if self.shuffle_questions: + all_questions = self.get_shuffled_questions(questions) + else: + all_questions = questions + return all_questions def make_answerpaper(self, user, ip, attempt_num): """Creates an answer paper for the user to attempt the quiz""" @@ -872,10 +877,11 @@ class QuestionPaper(models.Model): ans_paper.question_paper = self ans_paper.save() questions = self._get_questions_for_answerpaper() - for question in questions: - ans_paper.questions.add(question) - for question in questions: - ans_paper.questions_unanswered.add(question) + ans_paper.questions.add(*questions) + question_ids = [str(que.id) for que in questions] + ans_paper.questions_order = ",".join(question_ids) + ans_paper.save() + ans_paper.questions_unanswered.add(*questions) except AnswerPaper.MultipleObjectsReturned: ans_paper = AnswerPaper.objects.get(user=user, attempt_number=attempt_num, @@ -918,7 +924,7 @@ class QuestionPaper(models.Model): def create_demo_quiz_ppr(self, demo_quiz, user): question_paper = QuestionPaper.objects.create(quiz=demo_quiz, total_marks=6.0, - shuffle_questions=True + shuffle_questions=False ) summaries = ['Roots of quadratic equation', 'Print Output', 'Adding decimals', 'For Loop over String', @@ -941,9 +947,19 @@ class QuestionPaper(models.Model): for que_id in que_order: ques.append(self.fixed_questions.get(id=que_id)) else: - ques = self.fixed_questions.all() + ques = list(self.fixed_questions.all()) return ques + def get_shuffled_questions(self, questions): + """Get shuffled questions if auto suffle is enabled""" + random.shuffle(questions) + return questions + + def has_questions(self): + questions = self.get_ordered_questions() + \ + list(self.random_questions.all()) + return len(questions) > 0 + def __str__(self): return "Question Paper for " + self.quiz.description @@ -1164,13 +1180,27 @@ class AnswerPaper(models.Model): default='inprogress' ) + # set question order + questions_order = models.TextField(blank=True, default='') + objects = AnswerPaperManager() def current_question(self): """Returns the current active question to display.""" - if self.questions_unanswered.all(): - return self.questions_unanswered.all()[0] - return self.questions.all()[0] + questions = self.questions_unanswered.all() + if questions.exists(): + cur_question = self.get_current_question(questions) + else: + cur_question = self.get_current_question(self.questions.all()) + return cur_question + + def get_current_question(self, questions): + if self.questions_order: + question_id = int(self.questions_order.split(',')[0]) + question = self.questions_unanswered.get(id=question_id) + else: + question = questions.first() + return question def questions_left(self): """Returns the number of questions left.""" @@ -1195,17 +1225,30 @@ class AnswerPaper(models.Model): Skips the current question and returns the next sequentially available question. """ - all_questions = self.questions.all() - unanswered_questions = self.questions_unanswered.all() - questions = list(all_questions.values_list('id', flat=True)) - if len(questions) == 0: + if self.questions_order: + all_questions = [int(q_id) + for q_id in self.questions_order.split(',')] + else: + all_questions = list(self.questions.all().values_list( + 'id', flat=True)) + if len(all_questions) == 0: return None try: - index = questions.index(int(question_id)) - next_id = questions[index+1] + index = all_questions.index(int(question_id)) + next_id = all_questions[index+1] except (ValueError, IndexError): - next_id = questions[0] - return all_questions.get(id=next_id) + next_id = all_questions[0] + return self.questions.get(id=next_id) + + def get_all_ordered_questions(self): + """Get all questions in a specific order for answerpaper""" + if self.questions_order: + que_ids = [int(q_id) for q_id in self.questions_order.split(',')] + questions = [self.questions.get(id=que_id) + for que_id in que_ids] + else: + questions = list(self.questions.all()) + return questions def time_left(self): """Return the time remaining for the user in seconds.""" diff --git a/yaksh/templates/exam.html b/yaksh/templates/exam.html index 4d211d2..9596c1c 100644 --- a/yaksh/templates/exam.html +++ b/yaksh/templates/exam.html @@ -46,7 +46,7 @@ <div class="col-sm-3 col-md-2 sidebar"> <p> Question Navigator </p> <ul class="pagination pagination-sm"> - {% for qid in paper.questions.all %} + {% for qid in paper.get_all_ordered_questions %} {%if paper.question_paper.quiz.allow_skip %} {% if qid in paper.get_questions_unanswered %} {% if qid.id == question.id %} diff --git a/yaksh/test_models.py b/yaksh/test_models.py index 2c83024..03af521 100644 --- a/yaksh/test_models.py +++ b/yaksh/test_models.py @@ -502,6 +502,7 @@ class AnswerPaperTestCases(unittest.TestCase): def setUpClass(self): self.ip = '101.0.0.1' self.user = User.objects.get(username='demo_user') + self.user2 = User.objects.get(username='demo_user2') self.profile = self.user.profile self.quiz = Quiz.objects.get(description='demo quiz 1') self.question_paper = QuestionPaper(quiz=self.quiz, total_marks=3) @@ -590,6 +591,24 @@ class AnswerPaperTestCases(unittest.TestCase): ) self.mcc_based_testcase.save() + # Setup quiz where questions are shuffled + # Create Quiz and Question Paper + self.quiz2 = Quiz.objects.get(description="demo quiz 2") + self.question_paper2 = QuestionPaper( + quiz=self.quiz2, total_marks=3, shuffle_questions=True) + self.question_paper2.save() + summary_list = ['Q%d' % (i) for i in range(1, 21)] + que_list = Question.objects.filter(summary__in=summary_list) + self.question_paper2.fixed_questions.add(*que_list) + + # Create AnswerPaper for user1 and user2 + self.user1_answerpaper = self.question_paper2.make_answerpaper( + self.user, self.ip, 1 + ) + self.user2_answerpaper = self.question_paper2.make_answerpaper( + self.user2, self.ip, 1 + ) + def test_validate_and_regrade_mcc_correct_answer(self): # Given mcc_answer = [str(self.mcc_based_testcase.id)] @@ -663,7 +682,6 @@ class AnswerPaperTestCases(unittest.TestCase): self.assertEqual(self.answer.marks, 0) self.assertFalse(self.answer.correct) - def test_mcq_incorrect_answer(self): # Given mcq_answer = 'b' @@ -858,6 +876,11 @@ class AnswerPaperTestCases(unittest.TestCase): self.assertEqual(latest_answer.id, self.answer1.id) self.assertEqual(latest_answer.answer, "answer1") + def test_shuffle_questions(self): + ques_set_1 = self.user1_answerpaper.get_all_ordered_questions() + ques_set_2 = self.user2_answerpaper.get_all_ordered_questions() + self.assertFalse(ques_set_1 == ques_set_2) + ############################################################################### class CourseTestCases(unittest.TestCase): diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 2d86b77..dc06126 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -2092,13 +2092,13 @@ class TestViewAnswerPaper(TestCase): self.quiz = Quiz.objects.create(time_between_attempts=0, course=self.course, description='demo quiz', language='Python') - + self.user3 = User.objects.get(username="demo_user3") self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, total_marks=1.0) self.question_paper.fixed_questions.add(self.question) self.question_paper.save() - self.ans_paper = AnswerPaper.objects.create(user_id=3, + self.ans_paper = AnswerPaper.objects.create(user=self.user3, attempt_number=1, question_paper=self.question_paper, start_time=timezone.now(), user_ip='101.0.0.1', end_time=timezone.now()+timezone.timedelta(minutes=20)) @@ -2382,7 +2382,7 @@ class TestGrader(TestCase): self.question_paper.fixed_questions.add(self.question) self.question_paper.save() - self.answerpaper = AnswerPaper.objects.create(user_id=3, + self.answerpaper = AnswerPaper.objects.create(user=self.user2, attempt_number=1, question_paper=self.question_paper, start_time=timezone.now(), user_ip='101.0.0.1', end_time=timezone.now()+timezone.timedelta(minutes=20)) diff --git a/yaksh/views.py b/yaksh/views.py index 6abfa2b..b4cb844 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -392,8 +392,7 @@ def start(request, questionpaper_id=None, attempt_num=None): msg = 'Quiz not found, please contact your '\ 'instructor/administrator.' return complete(request, msg, attempt_num, questionpaper_id=None) - if not quest_paper.get_ordered_questions() and not \ - quest_paper.random_questions.all(): + if not quest_paper.has_questions(): msg = 'Quiz does not have Questions, please contact your '\ 'instructor/administrator.' return complete(request, msg, attempt_num, questionpaper_id=None) |