summaryrefslogtreecommitdiff
path: root/yaksh
diff options
context:
space:
mode:
Diffstat (limited to 'yaksh')
-rw-r--r--yaksh/models.py71
-rw-r--r--yaksh/views.py156
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