diff options
Diffstat (limited to 'yaksh/models.py')
-rw-r--r-- | yaksh/models.py | 677 |
1 files changed, 455 insertions, 222 deletions
diff --git a/yaksh/models.py b/yaksh/models.py index 7e97e6c..7ed87fe 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -121,6 +121,12 @@ def dict_to_yaml(dictionary): allow_unicode=True, ) + +def get_file_dir(instance, filename): + upload_dir = instance.lesson.name.replace(" ", "_") + return os.sep.join((upload_dir, filename)) + + ############################################################################### class CourseManager(models.Manager): @@ -134,6 +140,349 @@ class CourseManager(models.Manager): def get_hidden_courses(self, code): return self.filter(code=code, hidden=True) + +############################################################################# +class Lesson(models.Model): + # Lesson name + name = models.CharField(max_length=255) + + # Markdown text of lesson content + description = models.TextField() + + # Markdown text should be in html format + html_data = models.TextField(null=True, blank=True) + + # Creator of the lesson + creator = models.ForeignKey(User) + + def __str__(self): + return "{0}".format(self.name) + + def get_files(self): + return LessonFile.objects.filter(lesson=self) + + +############################################################################# +class LessonFile(models.Model): + lesson = models.ForeignKey(Lesson, related_name="lesson") + file = models.FileField(upload_to=get_file_dir) + + def remove(self): + if os.path.exists(self.file.path): + os.remove(self.file.path) + if os.listdir(os.path.dirname(self.file.path)) == []: + os.rmdir(os.path.dirname(self.file.path)) + self.delete() + + +############################################################################### +class QuizManager(models.Manager): + def get_active_quizzes(self): + return self.filter(active=True, is_trial=False) + + def create_trial_quiz(self, user): + """Creates a trial quiz for testing questions""" + trial_quiz = self.create(duration=1000, + description="trial_questions", + is_trial=True, + time_between_attempts=0, + creator=user + ) + return trial_quiz + + def create_trial_from_quiz(self, original_quiz_id, user, godmode, + course_id): + """Creates a trial quiz from existing quiz""" + trial_course_name = "Trial_course_for_course_{0}_{1}".format( + course_id, "godmode" if godmode else "usermode") + trial_quiz_name = "Trial_orig_id_{0}_{1}".format( + original_quiz_id, + "godmode" if godmode else "usermode" + ) + # Get or create Trial Course for usermode/godmode + trial_course = Course.objects.filter(name=trial_course_name) + if trial_course.exists(): + trial_course = trial_course.get(name=trial_course_name) + else: + trial_course = Course.objects.create( + name=trial_course_name, creator=user, enrollment="open", + is_trial=True) + + # Get or create Trial Quiz for usermode/godmode + if self.filter(description=trial_quiz_name).exists(): + trial_quiz = self.get(description=trial_quiz_name) + + else: + trial_quiz = self.get(id=original_quiz_id) + trial_quiz.user = user + trial_quiz.pk = None + trial_quiz.description = trial_quiz_name + trial_quiz.is_trial = True + trial_quiz.prerequisite = None + if godmode: + trial_quiz.time_between_attempts = 0 + trial_quiz.duration = 1000 + trial_quiz.attempts_allowed = -1 + trial_quiz.active = True + trial_quiz.start_date_time = timezone.now() + trial_quiz.end_date_time = datetime( + 2199, 1, 1, 0, 0, 0, 0, tzinfo=pytz.utc + ) + trial_quiz.save() + + # Get or create Trial Ordered Lesson for usermode/godmode + learning_modules = trial_course.get_learning_modules() + if learning_modules: + quiz = learning_modules[0].learning_unit.filter(quiz=trial_quiz) + if not quiz.exists(): + trial_learning_unit = LearningUnit.objects.create( + order=1, quiz=trial_quiz, type="quiz", + check_prerequisite=False) + learning_modules[0].learning_unit.add(trial_learning_unit.id) + trial_learning_module = learning_modules[0] + else: + trial_learning_module = LearningModule.objects.create( + name="Trial for {}".format(trial_course), order=1, + check_prerequisite=False, creator=user, is_trial=True) + trial_learning_unit = LearningUnit.objects.create( + order=1, quiz=trial_quiz, type="quiz", + check_prerequisite=False) + trial_learning_module.learning_unit.add(trial_learning_unit.id) + trial_course.learning_module.add(trial_learning_module.id) + + # Add user to trial_course + trial_course.enroll(False, user) + return trial_quiz, trial_course, trial_learning_module + + +############################################################################### +class Quiz(models.Model): + """A quiz that students will participate in. One can think of this + as the "examination" event. + """ + + # The start date of the quiz. + start_date_time = models.DateTimeField( + "Start Date and Time of the quiz", + default=timezone.now, + null=True + ) + + # The end date and time of the quiz + end_date_time = models.DateTimeField( + "End Date and Time of the quiz", + default=datetime( + 2199, 1, 1, + tzinfo=pytz.timezone(timezone.get_current_timezone_name()) + ), + null=True + ) + + # This is always in minutes. + duration = models.IntegerField("Duration of quiz in minutes", default=20) + + # Is the quiz active. The admin should deactivate the quiz once it is + # complete. + active = models.BooleanField(default=True) + + # Description of quiz. + description = models.CharField(max_length=256) + + # Mininum passing percentage condition. + pass_criteria = models.FloatField("Passing percentage", default=40) + + # Number of attempts for the quiz + attempts_allowed = models.IntegerField(default=1, choices=attempts) + + time_between_attempts = models.IntegerField( + "Number of Days", choices=days_between_attempts + ) + + is_trial = models.BooleanField(default=False) + + instructions = models.TextField('Instructions for Students', + default=None, blank=True, null=True) + + view_answerpaper = models.BooleanField('Allow student to view their answer\ + paper', default=False) + + allow_skip = models.BooleanField("Allow students to skip questions", + default=True) + + weightage = models.FloatField(default=1.0) + + creator = models.ForeignKey(User, null=True) + + objects = QuizManager() + + class Meta: + verbose_name_plural = "Quizzes" + + def is_expired(self): + return not self.start_date_time <= timezone.now() < self.end_date_time + + def create_demo_quiz(self, user): + demo_quiz = Quiz.objects.create( + start_date_time=timezone.now(), + end_date_time=timezone.now() + timedelta(176590), + duration=30, active=True, + attempts_allowed=-1, time_between_attempts=0, + description='Yaksh Demo quiz', pass_criteria=0, + creator=user + ) + return demo_quiz + + def get_total_students(self, course): + return AnswerPaper.objects.filter( + question_paper=self.questionpaper_set.get().id, + course=course + ).values_list("user", flat=True).distinct().count() + + def get_passed_students(self, course): + return AnswerPaper.objects.filter( + question_paper=self.questionpaper_set.get().id, + course=course, passed=True + ).values_list("user", flat=True).distinct().count() + + def get_failed_students(self, course): + return AnswerPaper.objects.filter( + question_paper=self.questionpaper_set.get().id, + course=course, passed=False + ).values_list("user", flat=True).distinct().count() + + def __str__(self): + desc = self.description or 'Quiz' + return '%s: on %s for %d minutes' % (desc, self.start_date_time, + self.duration) + + +########################################################################## +class LearningUnit(models.Model): + """ Maintain order of lesson and quiz added in the course """ + order = models.IntegerField() + type = models.CharField(max_length=16) + lesson = models.ForeignKey(Lesson, null=True, blank=True) + quiz = models.ForeignKey(Quiz, null=True, blank=True) + check_prerequisite = models.BooleanField(default=True) + + def toggle_check_prerequisite(self): + if self.check_prerequisite: + self.check_prerequisite = False + else: + self.check_prerequisite = True + + def get_completion_status(self, user, course): + course_status = CourseStatus.objects.filter(user=user, course=course) + state = "not attempted" + if course_status.exists(): + if self in course_status.first().completed_units.all(): + state = "completed" + elif course_status.first().current_unit == self: + state = "inprogress" + return state + + def has_prerequisite(self): + return self.check_prerequisite + + def is_prerequisite_passed(self, user, learning_module, course): + ordered_units = learning_module.learning_unit.order_by("order") + ordered_units_ids = list(ordered_units.values_list("id", flat=True)) + current_unit_index = ordered_units_ids.index(self.id) + if current_unit_index == 0: + success = True + else: + prev_unit = ordered_units.get( + id=ordered_units_ids[current_unit_index-1]) + status = prev_unit.get_completion_status(user, course) + if status == "completed": + success = True + else: + success = False + return success + + +############################################################################### +class LearningModule(models.Model): + """ Learning Module to maintain learning units""" + learning_unit = models.ManyToManyField(LearningUnit, + related_name="learning_unit") + name = models.CharField(max_length=255) + description = models.TextField(default=None, null=True, blank=True) + order = models.IntegerField(default=0) + creator = models.ForeignKey(User, related_name="module_creator") + check_prerequisite = models.BooleanField(default=True) + html_data = models.TextField(null=True, blank=True) + is_trial = models.BooleanField(default=False) + + def get_quiz_units(self): + return [unit.quiz for unit in self.learning_unit.filter( + type="quiz")] + + def get_learning_units(self): + return self.learning_unit.order_by("order") + + def get_added_quiz_lesson(self): + learning_units = self.learning_unit.order_by("order") + added_quiz_lessons = [] + if learning_units.exists(): + for unit in learning_units: + if unit.type == "quiz": + added_quiz_lessons.append(("quiz", unit.quiz)) + else: + added_quiz_lessons.append(("lesson", unit.lesson)) + return added_quiz_lessons + + def toggle_check_prerequisite(self): + self.check_prerequisite = not self.check_prerequisite + + def get_next_unit(self, current_unit_id): + ordered_units = self.learning_unit.order_by("order") + ordered_units_ids = list(ordered_units.values_list("id", flat=True)) + current_unit_index = ordered_units_ids.index(current_unit_id) + next_index = current_unit_index + 1 + if next_index == len(ordered_units_ids): + next_index = 0 + return ordered_units.get(id=ordered_units_ids[next_index]) + + def get_status(self, user, course): + """ Get module status if it completed, inprogress or not attempted""" + learning_module = course.learning_module.prefetch_related( + "learning_unit").get(id=self.id) + ordered_units = learning_module.learning_unit.order_by("order") + status_list = [unit.get_completion_status(user, course) + for unit in ordered_units] + if all([status == "completed" for status in status_list]): + return "completed" + elif "inprogress" in status_list: + return "inprogress" + else: + return "not attempted" + + def is_prerequisite_passed(self, user, course): + """ Check if prerequisite module is completed """ + ordered_modules = course.learning_module.order_by("order") + ordered_modules_ids = list(ordered_modules.values_list( + "id", flat=True)) + current_module_index = ordered_modules_ids.index(self.id) + if current_module_index == 0: + success = True + else: + prev_module = ordered_modules.get( + id=ordered_modules_ids[current_module_index-1]) + status = prev_module.get_status(user, course) + if status == "completed": + success = True + else: + success = False + return success + + def has_prerequisite(self): + return self.check_prerequisite + + def __str__(self): + return self.name + + ############################################################################### class Course(models.Model): """ Course for students""" @@ -150,6 +499,8 @@ class Course(models.Model): teachers = models.ManyToManyField(User, related_name='teachers') is_trial = models.BooleanField(default=False) instructions = models.TextField(default=None, null=True, blank=True) + learning_module = models.ManyToManyField(LearningModule, + related_name='learning_module') # The start date of the course enrollment. start_enroll_time = models.DateTimeField( @@ -179,30 +530,12 @@ class Course(models.Model): return new_course def create_duplicate_course(self, user): - quizzes = self.quiz_set.all() - prerequisite_map = [] - duplicate_quiz_map = {} + learning_modules = self.learning_module.all() new_course_name = "Copy Of {0}".format(self.name) new_course = self._create_duplicate_instance(user, new_course_name) - for q in quizzes: - new_quiz = q._create_duplicate_quiz(new_course) - if q.id not in duplicate_quiz_map.keys(): - duplicate_quiz_map[q.id] = new_quiz.id - - for orig_qid, dupl_qid in duplicate_quiz_map.items(): - original_quiz = Quiz.objects.get(id=orig_qid) - if original_quiz.prerequisite: - duplicate_quiz = Quiz.objects.get(id=dupl_qid) - prereq_id = original_quiz.prerequisite.id - duplicate_prereq_id = duplicate_quiz_map.get(prereq_id) - if duplicate_prereq_id: - duplicate_prerequisite = Quiz.objects.get( - id=duplicate_prereq_id - ) - duplicate_quiz.prerequisite = duplicate_prerequisite - duplicate_quiz.save() + new_course.learning_module.add(*learning_modules) return new_course @@ -247,9 +580,6 @@ class Course(models.Model): def is_self_enroll(self): return True if self.enrollment == enrollment_methods[1][0] else False - def get_quizzes(self): - return self.quiz_set.filter(is_trial=False) - def activate(self): self.active = True @@ -266,18 +596,25 @@ class Course(models.Model): self.teachers.remove(*teachers) def create_demo(self, user): - course = Course.objects.filter(creator=user, name="Yaksh Demo course") + course = Course.objects.filter(creator=user, + name="Yaksh Demo course").exists() if not course: course = Course.objects.create(name="Yaksh Demo course", enrollment="open", creator=user) quiz = Quiz() - demo_quiz = quiz.create_demo_quiz(course) + demo_quiz = quiz.create_demo_quiz(user) demo_ques = Question() demo_ques.create_demo_questions(user) demo_que_ppr = QuestionPaper() demo_que_ppr.create_demo_quiz_ppr(demo_quiz, user) success = True + ordered_unit = LearningUnit.objects.create( + order=1, type="quiz", quiz=demo_quiz) + learning_module = LearningModule.objects.create( + name="demo module", description="demo module", creator=user) + learning_module.learning_unit.add(ordered_unit) + course.learning_module.add(learning_module) else: success = False return success @@ -288,11 +625,57 @@ class Course(models.Model): students = self.students.exclude(id__in=teachers) return students + def get_learning_modules(self): + return self.learning_module.order_by("order") + + def get_unit_completion_status(self, module, user, unit): + course_module = self.learning_module.get(id=module.id) + learning_unit = course_module.learning_unit.get(id=unit.id) + return learning_unit.get_completion_status(user, self) + + def get_quizzes(self): + learning_modules = self.learning_module.all() + quiz_list = [] + for module in learning_modules: + quiz_list.extend(module.get_quiz_units()) + return quiz_list + + def get_quiz_details(self): + return [(quiz, quiz.get_total_students(self), + quiz.get_passed_students(self), + quiz.get_failed_students(self)) + for quiz in self.get_quizzes()] + + def get_learning_units(self): + learning_modules = self.learning_module.all() + learning_units = [] + for module in learning_modules: + learning_units.extend(module.get_learning_units()) + return learning_units + + def remove_trial_modules(self): + learning_modules = self.learning_module.all() + for module in learning_modules: + module.learning_unit.all().delete() + learning_modules.delete() + def __str__(self): return self.name ############################################################################### +class CourseStatus(models.Model): + completed_units = models.ManyToManyField(LearningUnit, + related_name="completed_units") + current_unit = models.ForeignKey(LearningUnit, related_name="current_unit", + null=True, blank=True) + course = models.ForeignKey(Course) + user = models.ForeignKey(User) + grade = models.CharField(max_length=255, null=True, blank=True) + total_marks = models.FloatField(default=0.0) + + +############################################################################### class ConcurrentUser(models.Model): concurrent_user = models.OneToOneField(User) session_key = models.CharField(max_length=40) @@ -621,165 +1004,6 @@ class Answer(models.Model): ############################################################################### -class QuizManager(models.Manager): - def get_active_quizzes(self): - return self.filter(active=True, is_trial=False) - - def create_trial_quiz(self, trial_course, user): - """Creates a trial quiz for testing questions""" - trial_quiz = self.create(course=trial_course, - duration=1000, - description="trial_questions", - is_trial=True, - time_between_attempts=0 - ) - return trial_quiz - - def create_trial_from_quiz(self, original_quiz_id, user, godmode): - """Creates a trial quiz from existing quiz""" - trial_quiz_name = "Trial_orig_id_{0}_{1}".format( - original_quiz_id, - "godmode" if godmode else "usermode" - ) - - if self.filter(description=trial_quiz_name).exists(): - trial_quiz = self.get(description=trial_quiz_name) - - else: - trial_quiz = self.get(id=original_quiz_id) - trial_quiz.course.enroll(False, user) - trial_quiz.pk = None - trial_quiz.description = trial_quiz_name - trial_quiz.is_trial = True - trial_quiz.prerequisite = None - if godmode: - trial_quiz.time_between_attempts = 0 - trial_quiz.duration = 1000 - trial_quiz.attempts_allowed = -1 - trial_quiz.active = True - trial_quiz.start_date_time = timezone.now() - trial_quiz.end_date_time = datetime( - 2199, 1, 1, 0, 0, 0, 0, tzinfo=pytz.utc - ) - trial_quiz.save() - return trial_quiz - - -############################################################################### -class Quiz(models.Model): - """A quiz that students will participate in. One can think of this - as the "examination" event. - """ - - course = models.ForeignKey(Course) - - # The start date of the quiz. - start_date_time = models.DateTimeField( - "Start Date and Time of the quiz", - default=timezone.now, - null=True - ) - - # The end date and time of the quiz - end_date_time = models.DateTimeField( - "End Date and Time of the quiz", - default=datetime( - 2199, 1, 1, - tzinfo=pytz.timezone(timezone.get_current_timezone_name()) - ), - null=True - ) - - # This is always in minutes. - duration = models.IntegerField("Duration of quiz in minutes", default=20) - - # Is the quiz active. The admin should deactivate the quiz once it is - # complete. - active = models.BooleanField(default=True) - - # Description of quiz. - description = models.CharField(max_length=256) - - # Mininum passing percentage condition. - pass_criteria = models.FloatField("Passing percentage", default=40) - - # List of prerequisite quizzes to be passed to take this quiz - prerequisite = models.ForeignKey("Quiz", null=True, blank=True) - - # Programming language for a quiz - language = models.CharField(max_length=20, choices=languages) - - # Number of attempts for the quiz - attempts_allowed = models.IntegerField(default=1, choices=attempts) - - time_between_attempts = models.IntegerField( - "Number of Days", choices=days_between_attempts - ) - - is_trial = models.BooleanField(default=False) - - instructions = models.TextField('Instructions for Students', - default=None, blank=True, null=True) - - view_answerpaper = models.BooleanField('Allow student to view their answer\ - paper', default=False) - - allow_skip = models.BooleanField("Allow students to skip questions", - default=True) - - objects = QuizManager() - - class Meta: - verbose_name_plural = "Quizzes" - - def is_expired(self): - return not self.start_date_time <= timezone.now() < self.end_date_time - - def has_prerequisite(self): - return True if self.prerequisite else False - - def _create_duplicate_quiz(self, course): - questionpaper = self.questionpaper_set.all() - new_quiz = Quiz.objects.create(course=course, - start_date_time=self.start_date_time, - end_date_time=self.end_date_time, - duration=self.duration, - active=self.active, - description="Copy Of {0}".format(self.description), - pass_criteria=self.pass_criteria, - language=self.language, - attempts_allowed=self.attempts_allowed, - time_between_attempts=self.time_between_attempts, - is_trial=self.is_trial, - instructions=self.instructions, - allow_skip=self.allow_skip - ) - - for qp in questionpaper: - qp._create_duplicate_questionpaper(new_quiz) - - return new_quiz - - def create_demo_quiz(self, course): - demo_quiz = Quiz.objects.create( - start_date_time=timezone.now(), - end_date_time=timezone.now() + timedelta(176590), - duration=30, active=True, - attempts_allowed=-1, - time_between_attempts=0, - description='Yaksh Demo quiz', pass_criteria=0, - language='Python', prerequisite=None, - course=course - ) - return demo_quiz - - def __str__(self): - desc = self.description or 'Quiz' - return '%s: on %s for %d minutes' % (desc, self.start_date_time, - self.duration) - - -############################################################################### class QuestionPaperManager(models.Manager): def _create_trial_from_questionpaper(self, original_quiz_id): @@ -884,18 +1108,20 @@ class QuestionPaper(models.Model): all_questions = questions return all_questions - def make_answerpaper(self, user, ip, attempt_num): + def make_answerpaper(self, user, ip, attempt_num, course_id): """Creates an answer paper for the user to attempt the quiz""" try: ans_paper = AnswerPaper.objects.get(user=user, attempt_number=attempt_num, - question_paper=self + question_paper=self, + course_id=course_id ) except AnswerPaper.DoesNotExist: ans_paper = AnswerPaper( user=user, user_ip=ip, - attempt_number=attempt_num + attempt_number=attempt_num, + course_id=course_id ) ans_paper.start_time = timezone.now() ans_paper.end_time = ans_paper.start_time + \ @@ -911,25 +1137,22 @@ class QuestionPaper(models.Model): except AnswerPaper.MultipleObjectsReturned: ans_paper = AnswerPaper.objects.get(user=user, attempt_number=attempt_num, - question_paper=self + question_paper=self, + course_id=course_id ).order_by('-id') ans_paper = ans_paper[0] return ans_paper - def _is_questionpaper_passed(self, user): - return AnswerPaper.objects.filter(question_paper=self, user=user, - passed=True).exists() - def _is_attempt_allowed(self, user): attempts = AnswerPaper.objects.get_total_attempt(questionpaper=self, user=user) return attempts != self.quiz.attempts_allowed - def can_attempt_now(self, user): + def can_attempt_now(self, user, course_id): if self._is_attempt_allowed(user): last_attempt = AnswerPaper.objects.get_user_last_attempt( - user=user, questionpaper=self + user=user, questionpaper=self, course_id=course_id ) if last_attempt: time_lag = (timezone.now() - last_attempt.start_time).days @@ -939,14 +1162,6 @@ class QuestionPaper(models.Model): else: return False - def _get_prequisite_paper(self): - return self.quiz.prerequisite.questionpaper_set.get() - - def is_prerequisite_passed(self, user): - if self.quiz.has_prerequisite(): - prerequisite = self._get_prequisite_paper() - return prerequisite._is_questionpaper_passed(user) - def create_demo_quiz_ppr(self, demo_quiz, user): question_paper = QuestionPaper.objects.create(quiz=demo_quiz, shuffle_questions=False @@ -1038,27 +1253,32 @@ class AnswerPaperManager(models.Manager): questions_answered.append(question.id) return Counter(questions_answered) - def get_attempt_numbers(self, questionpaper_id, status='completed'): + def get_attempt_numbers(self, questionpaper_id, course_id, + status='completed'): ''' Return list of attempt numbers''' attempt_numbers = self.filter( - question_paper_id=questionpaper_id, status=status + question_paper_id=questionpaper_id, status=status, + course_id=course_id ).values_list('attempt_number', flat=True).distinct() return attempt_numbers - def has_attempt(self, questionpaper_id, attempt_number, + def has_attempt(self, questionpaper_id, attempt_number, course_id, status='completed'): ''' Whether question paper is attempted''' return self.filter( question_paper_id=questionpaper_id, - attempt_number=attempt_number, status=status + attempt_number=attempt_number, status=status, + course_id=course_id ).exists() - def get_count(self, questionpaper_id, attempt_number, status='completed'): + def get_count(self, questionpaper_id, attempt_number, course_id, + status='completed'): ''' Return count of answerpapers for a specfic question paper and attempt number''' return self.filter( question_paper_id=questionpaper_id, - attempt_number=attempt_number, status=status + attempt_number=attempt_number, status=status, + course_id=course_id ).count() def get_question_statistics(self, questionpaper_id, attempt_number, @@ -1083,18 +1303,21 @@ class AnswerPaperManager(models.Manager): question_stats[question] = [0, questions[question.id]] return question_stats - def _get_answerpapers_for_quiz(self, questionpaper_id, status=False): + def _get_answerpapers_for_quiz(self, questionpaper_id, course_id, + status=False): if not status: - return self.filter(question_paper_id=questionpaper_id) + return self.filter(question_paper_id=questionpaper_id, + course_id=course_id) else: return self.filter(question_paper_id=questionpaper_id, + course_id=course_id, status="completed") def _get_answerpapers_users(self, answerpapers): return answerpapers.values_list('user', flat=True).distinct() - def get_latest_attempts(self, questionpaper_id): - papers = self._get_answerpapers_for_quiz(questionpaper_id) + def get_latest_attempts(self, questionpaper_id, course_id): + papers = self._get_answerpapers_for_quiz(questionpaper_id, course_id) users = self._get_answerpapers_users(papers) latest_attempts = [] for user in users: @@ -1106,9 +1329,10 @@ class AnswerPaperManager(models.Manager): user_id=user_id ).order_by('-attempt_number')[0] - def get_user_last_attempt(self, questionpaper, user): + def get_user_last_attempt(self, questionpaper, user, course_id): attempts = self.filter(question_paper=questionpaper, - user=user).order_by('-attempt_number') + user=user, + course_id=course_id).order_by('-attempt_number') if attempts: return attempts[0] @@ -1118,23 +1342,28 @@ class AnswerPaperManager(models.Manager): def get_total_attempt(self, questionpaper, user): return self.filter(question_paper=questionpaper, user=user).count() - def get_users_for_questionpaper(self, questionpaper_id): - return self._get_answerpapers_for_quiz(questionpaper_id, status=True)\ + def get_users_for_questionpaper(self, questionpaper_id, course_id): + return self._get_answerpapers_for_quiz(questionpaper_id, course_id, + status=True)\ .values("user__id", "user__first_name", "user__last_name")\ .order_by("user__first_name")\ .distinct() - def get_user_all_attempts(self, questionpaper, user): - return self.filter(question_paper=questionpaper, user=user)\ + def get_user_all_attempts(self, questionpaper, user, course_id): + return self.filter(question_paper=questionpaper, user=user, + course_id=course_id)\ .order_by('-attempt_number') - def get_user_data(self, user, questionpaper_id, attempt_number=None): + def get_user_data(self, user, questionpaper_id, course_id, + attempt_number=None): if attempt_number is not None: papers = self.filter(user=user, question_paper_id=questionpaper_id, + course_id=course_id, attempt_number=attempt_number) else: papers = self.filter( - user=user, question_paper_id=questionpaper_id + user=user, question_paper_id=questionpaper_id, + course_id=course_id ).order_by("-attempt_number") data = {} profile = user.profile if hasattr(user, 'profile') else None @@ -1144,9 +1373,9 @@ class AnswerPaperManager(models.Manager): data['questionpaperid'] = questionpaper_id return data - def get_user_best_of_attempts_marks(self, quiz, user_id): + def get_user_best_of_attempts_marks(self, quiz, user_id, course_id): best_attempt = 0.0 - papers = self.filter(question_paper__quiz=quiz, + papers = self.filter(question_paper__quiz=quiz, course_id=course_id, user=user_id).values("marks_obtained") if papers: best_attempt = max([marks["marks_obtained"] for marks in papers]) @@ -1165,6 +1394,9 @@ class AnswerPaper(models.Model): # The Quiz to which this question paper is attached to. question_paper = models.ForeignKey(QuestionPaper) + # Answepaper will be unique to the course + course = models.ForeignKey(Course, null=True) + # The attempt number for the question paper. attempt_number = models.IntegerField() @@ -1438,6 +1670,7 @@ class AnswerPaper(models.Model): result['error'] = ['Correct answer'] elif question.type == 'float': + user_answer = float(user_answer) tc_status = [] user_answer = float(user_answer) for tc in question.get_test_cases(): |