diff options
Diffstat (limited to 'yaksh')
-rw-r--r-- | yaksh/models.py | 71 | ||||
-rw-r--r-- | yaksh/views.py | 156 |
2 files changed, 113 insertions, 114 deletions
diff --git a/yaksh/models.py b/yaksh/models.py index a475493..b0247ac 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -991,13 +991,13 @@ class Course(models.Model): return self.rejected.all() def is_enrolled(self, user): - return user in self.students.all() + return self.students.filter(id=user.id).exists() def is_creator(self, user): return self.creator == user def is_teacher(self, user): - return True if user in self.teachers.all() else False + return self.teachers.filter(id=user.id).exists() def is_self_enroll(self): return True if self.enrollment == enrollment_methods[1][0] else False @@ -1061,7 +1061,7 @@ class Course(models.Model): return success def get_only_students(self): - teachers = list(self.teachers.all().values_list("id", flat=True)) + teachers = list(self.teachers.values_list("id", flat=True)) teachers.append(self.creator.id) students = self.students.exclude(id__in=teachers) return students @@ -1180,7 +1180,7 @@ class Course(models.Model): return percentage def is_student(self, user): - return user in self.students.all() + return self.students.filter(id=user.id).exists() def create_zip(self, path, static_files): zip_file_name = string_io() @@ -2171,11 +2171,38 @@ class AnswerPaperManager(models.Manager): best_attempt = 0.0 papers = self.filter(question_paper__quiz_id=quiz.id, course_id=course_id, - user=user_id).values("marks_obtained") - if papers: - best_attempt = max([marks["marks_obtained"] for marks in papers]) + user=user_id).order_by("-marks_obtained").values( + "marks_obtained") + if papers.exists(): + best_attempt = papers[0]["marks_obtained"] return best_attempt + def get_user_scores(self, question_papers, user, course_id): + qp_ids = list(zip(*question_papers))[0] + papers = self.filter( + course_id=course_id, user_id=user.get("id"), + question_paper__id__in=qp_ids + ).values("question_paper_id", "marks_obtained") + df = pd.DataFrame(papers) + user_marks = 0 + ap_data = None + if not df.empty: + ap_data = df.groupby("question_paper_id").tail(1) + for qp_id, quiz, quiz_marks in question_papers: + if ap_data is not None: + qp = ap_data['question_paper_id'].to_list() + marks = ap_data['marks_obtained'].to_list() + if qp_id in qp: + idx = qp.index(qp_id) + user_marks += marks[idx] + user[f"{quiz}-{quiz_marks}-Marks"] = marks[idx] + else: + user[f"{quiz}-{quiz_marks}-Marks"] = 0 + else: + user[f"{quiz}-{quiz_marks}-Marks"] = 0 + user.pop("id") + user["total_marks"] = user_marks + ############################################################################### class AnswerPaper(models.Model): @@ -2249,15 +2276,27 @@ class AnswerPaper(models.Model): 'attempt_number', "course" ) - def get_per_question_score(self, question_id): - questions = self.get_questions().values_list('id', flat=True) - if question_id not in questions: - return 'NA' - answer = self.get_latest_answer(question_id) - if answer: - return answer.marks - else: - return 0 + def get_per_question_score(self, question_ids): + que_ids = list(zip(*question_ids))[1] + answers = self.answers.filter( + question_id__in=que_ids).values("question_id", "marks") + que_data = {} + df = pd.DataFrame(answers) + ans_data = None + if not df.empty: + ans_data = df.groupby("question_id").tail(1) + for que_summary, que_id in question_ids: + if ans_data is not None: + ans = ans_data['question_id'].to_list() + marks = ans_data['marks'].to_list() + if que_id in ans: + idx = ans.index(que_id) + que_data[que_summary] = marks[idx] + else: + que_data[que_summary] = 0 + else: + que_data[que_summary] = 0 + return que_data def current_question(self): """Returns the current active question to display.""" diff --git a/yaksh/views.py b/yaksh/views.py index 50f9ded..32d1e72 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -26,6 +26,7 @@ from textwrap import dedent import zipfile import markdown import ruamel +import pandas as pd try: from StringIO import StringIO as string_io except ImportError: @@ -80,7 +81,10 @@ def is_moderator(user, group_name=MOD_GROUP_NAME): """Check if the user is having moderator rights""" try: group = Group.objects.get(name=group_name) - return user.profile.is_moderator and user in group.user_set.all() + return ( + user.profile.is_moderator and + group.user_set.filter(id=user.id).exists() + ) except Profile.DoesNotExist: return False except Group.DoesNotExist: @@ -706,7 +710,7 @@ def show_question(request, question, paper, error_message=None, ) else: quiz_type = 'Exercise' - if question in paper.questions_answered.all(): + if paper.questions_answered.filter(id=question.id).exists(): notification = ( 'You have already attempted this question successfully' if question.type == "code" else @@ -1840,80 +1844,40 @@ def download_quiz_csv(request, course_id, quiz_id): if not course.is_creator(current_user) and \ not course.is_teacher(current_user): raise Http404('The quiz does not belong to your course') - users = course.get_enrolled().order_by('first_name') - if not users: - return monitor(request, quiz_id) - csv_fields = [] - attempt_number = None question_paper = quiz.questionpaper_set.last() - last_attempt_number = AnswerPaper.objects.get_attempt_numbers( - question_paper.id, course.id).last() if request.method == 'POST': csv_fields = request.POST.getlist('csv_fields') - attempt_number = request.POST.get('attempt_number', - last_attempt_number) - if not csv_fields: - csv_fields = CSV_FIELDS - if not attempt_number: - attempt_number = last_attempt_number - - questions = question_paper.get_question_bank() - answerpapers = AnswerPaper.objects.filter( - question_paper=question_paper, - attempt_number=attempt_number, course_id=course_id) - if not answerpapers: - return monitor(request, quiz_id, course_id) - response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = \ - 'attachment; filename="{0}-{1}-attempt{2}.csv"'.format( - course.name.replace('.', ''), quiz.description.replace('.', ''), - attempt_number) - writer = csv.writer(response) - if 'questions' in csv_fields: - csv_fields = _expand_questions(questions, csv_fields) - writer.writerow(csv_fields) - - csv_fields_values = { - 'name': 'user.get_full_name().title()', - 'roll_number': 'user.profile.roll_number', - 'institute': 'user.profile.institute', - 'department': 'user.profile.department', - 'username': 'user.username', - 'marks_obtained': 'answerpaper.marks_obtained', - 'out_of': 'question_paper.total_marks', - 'percentage': 'answerpaper.percent', - 'status': 'answerpaper.status'} - questions_scores = {} - for question in questions: - questions_scores['Q-{0}-{1}-{2}-marks'.format( - question.id, question.summary, question.points)] \ - = 'answerpaper.get_per_question_score({0})'.format(question.id) - answer = question.answer_set.last() - comment = None - if answer: - comment = answer.comment - else: - comment = '' - questions_scores['Q-{0}-{1}-comments'.format( - question.id, question.summary)] \ - = 'answerpaper.get_answer_comment({0})'.format(question.id) - csv_fields_values.update(questions_scores) - - users = users.exclude(id=course.creator.id).exclude( - id__in=course.teachers.all()) - for user in users: - row = [] - answerpaper = None - papers = answerpapers.filter(user=user) - if papers: - answerpaper = papers.first() - for field in csv_fields: - try: - row.append(eval(csv_fields_values[field])) - except AttributeError: - row.append('-') - writer.writerow(row) - return response + attempt_number = request.POST.get('attempt_number') + questions = question_paper.get_question_bank() + answerpapers = AnswerPaper.objects.select_related( + "user").select_related('question_paper').prefetch_related( + 'answers').filter( + course_id=course_id, question_paper_id=question_paper.id, + attempt_number=attempt_number + ).order_by("user__first_name") + que_summaries = [ + (f"{que.summary}-{que.points}-marks", que.id) for que in questions + ] + user_data = list(answerpapers.values( + "user__first_name", "user__last_name", + "user__profile__roll_number", "user__profile__institute", + "user__profile__department", "marks_obtained", + "question_paper__total_marks", "percent", "status" + )) + for idx, ap in enumerate(answerpapers): + que_data = ap.get_per_question_score(que_summaries) + user_data[idx].update(que_data) + df = pd.DataFrame(user_data) + response = HttpResponse(content_type='text/csv') + response['Content-Disposition'] = \ + 'attachment; filename="{0}-{1}-attempt-{2}.csv"'.format( + course.name.replace(' ', '_'), + quiz.description.replace(' ', '_'), attempt_number + ) + output_file = df.to_csv(response, index=False) + return response + else: + return monitor(request, quiz_id) @login_required @@ -2295,40 +2259,36 @@ def download_course_csv(request, course_id): user = request.user if not is_moderator(user): raise Http404('You are not allowed to view this page!') - course = Course.objects.prefetch_related("learning_module").get( - id=course_id) + course = get_object_or_404( + Course.objects.prefetch_related("learning_module"), id=course_id + ) if not course.is_creator(user) and not course.is_teacher(user): - raise Http404('The question paper does not belong to your course') - students = course.get_only_students().annotate( + raise Http404('You are not allowed to view this course') + students = list(course.get_only_students().annotate( roll_number=F('profile__roll_number'), institute=F('profile__institute') ).values( - "id", "first_name", "last_name", - "email", "institute", "roll_number" - ) - quizzes = course.get_quizzes() - + "id", "first_name", "last_name", "email", "institute", "roll_number" + )) + que_pprs = [ + quiz.questionpaper_set.values( + "id", "quiz__description", "total_marks")[0] + for quiz in course.get_quizzes() + ] + total_course_marks = sum([qp.get("total_marks", 0) for qp in que_pprs]) + qp_ids = [ + (qp.get("id"), qp.get("quiz__description"), qp.get("total_marks")) + for qp in que_pprs + ] for student in students: - total_course_marks = 0.0 user_course_marks = 0.0 - for quiz in quizzes: - quiz_best_marks = AnswerPaper.objects. \ - get_user_best_of_attempts_marks(quiz, student["id"], course_id) - user_course_marks += quiz_best_marks - total_course_marks += quiz.questionpaper_set.values_list( - "total_marks", flat=True)[0] - student["{}".format(quiz.description)] = quiz_best_marks - student["total_scored"] = user_course_marks + AnswerPaper.objects.get_user_scores(qp_ids, student, course_id) student["out_of"] = total_course_marks + df = pd.DataFrame(students) response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename="{0}.csv"'.format( - (course.name).lower().replace('.', '')) - header = ['first_name', 'last_name', "roll_number", "email", "institute"]\ - + [quiz.description for quiz in quizzes] + ['total_scored', 'out_of'] - writer = csv.DictWriter(response, fieldnames=header, extrasaction='ignore') - writer.writeheader() - for student in students: - writer.writerow(student) + (course.name).lower().replace(' ', '_')) + output_file = df.to_csv(response, index=False) return response |