From 7f28b418b616823f542faea8311e881faf6286c2 Mon Sep 17 00:00:00 2001 From: adityacp Date: Tue, 26 Jan 2021 14:38:46 +0530 Subject: Refactor question statistics for a quiz --- yaksh/models.py | 65 +++++++------ yaksh/templates/yaksh/statistics_question.html | 123 ++++++++++--------------- yaksh/templatetags/custom_filters.py | 4 +- yaksh/test_views.py | 8 +- yaksh/views.py | 11 ++- 5 files changed, 99 insertions(+), 112 deletions(-) (limited to 'yaksh') diff --git a/yaksh/models.py b/yaksh/models.py index 3e3e2d1..bbb6900 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -2063,36 +2063,45 @@ class AnswerPaperManager(models.Manager): def get_question_statistics(self, questionpaper_id, attempt_number, course_id, status='completed'): ''' Return dict with question object as key and list as value - The list contains two value, first the number of times a question - was answered correctly, and second the number of times a question - appeared in a quiz''' + The list contains four values, first total attempts, second correct + attempts, third correct percentage, fourth per test case answers + a question + ''' question_stats = {} - questions_answered = self.get_all_questions_answered(questionpaper_id, - attempt_number, - course_id) - questions = self.get_all_questions(questionpaper_id, attempt_number, - course_id) - per_answer_stats = self.get_per_answer_stats( - questionpaper_id, attempt_number, course_id + qp = QuestionPaper.objects.get(id=questionpaper_id) + all_questions = qp.get_question_bank() + que_ids = [que.id for que in all_questions] + papers = self.filter( + question_paper_id=questionpaper_id, course_id=course_id, + attempt_number=attempt_number + ).values_list("id", flat=True) + answers = Answer.objects.filter( + answerpaper__id__in=papers, question_id__in=que_ids + ).order_by("id").values( + "answerpaper__id", "question_id", "correct", "answer" ) - all_questions = Question.objects.filter( - id__in=set(questions), - active=True - ).order_by('type') - for question in all_questions: - if question.id in questions_answered: - question_stats[question] = { - 'answered': [questions_answered[question.id], - questions[question.id]], - 'per_answer': per_answer_stats[question], - } - - else: - question_stats[question] = { - 'answered': [0, questions[question.id]], - 'per_answer': per_answer_stats[question], - } - + def _get_per_tc_data(answers, q_type): + tc = [] + for answer in answers["answer"]: + ans = literal_eval(answer) if answer else None + tc.extend(ans) if q_type == "mcc" else tc.append(str(ans)) + return dict(Counter(tc)) + df = pd.DataFrame(answers) + if not df.empty: + for question in all_questions: + que = df[df["question_id"]==question.id].groupby( + "answerpaper__id").tail(1) + if not que.empty: + total_attempts = que.shape[0] + correct_attempts = que[que["correct"]==True].shape[0] + per_tc_ans = {} + if question.type in ["mcq", "mcc"]: + per_tc_ans = _get_per_tc_data(que, question.type) + question_stats[question] = ( + total_attempts, correct_attempts, + round((correct_attempts/total_attempts)*100), + per_tc_ans + ) return question_stats def _get_answerpapers_for_quiz(self, questionpaper_id, course_id, diff --git a/yaksh/templates/yaksh/statistics_question.html b/yaksh/templates/yaksh/statistics_question.html index d70256b..588e131 100644 --- a/yaksh/templates/yaksh/statistics_question.html +++ b/yaksh/templates/yaksh/statistics_question.html @@ -18,10 +18,25 @@
+ {% if messages %} + {% for message in messages %} +
+ + {{ message }} +
+ {% endfor %} + {% endif %} {% if question_stats %}

Total number of participants: {{ total }}

- + + + + + + {% for question, data in question_stats.items %} - - - - + + + {% endfor %}
QuestionTypeTotalAnswered Correctly
QuestionTypeTotal attemptsAnswered Correctly
@@ -40,7 +55,7 @@ Description: -

+

{{ question.description|safe }}

@@ -55,87 +70,49 @@

{{ question.get_type_display }}

- {% if question.type in 'mcq mcc' %} - - Options: - -

-

    - {% for tc in question.testcase_set.all %} -
  1. - {{ tc.mcqtestcase.options }} - {% if tc.mcqtestcase.correct %} - Correct - {% endif %} - {% get_dict_value data.per_answer tc.id|stringformat:"i" as num %} - Answered: {{ num }} -
  2. + {% if question.type in "mcq mcc" %} + {% for tc in question.get_test_cases %} + {% if tc.correct %} + + {{forloop.counter}}. + + {% else %} + + {{ forloop.counter }}. + + {% endif %} + {{tc.options}} + {% get_percent_value data.3 tc.id total as percent %} +
    +
    +
    + + {% if percent %} {{percent|floatformat}} {% else %} 0 {% endif %}% + +
    +
    +
    + {% if percent %} +
    +
    + {% endif %} +
    +
    +
    {% endfor %} -
-

{% endif %}
{{ question.type }}{{data.answered.1}}{{ data.answered.0 }} ({% widthratio data.answered.0 data.answered.1 100 %}%){{ question.get_type_display }}{{data.0}} out of {{total}}{{ data.1 }} out of {{data.0}} ({{data.2}}%)
{% endif %} - - - - -
- - diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py index 81572a7..201ec50 100644 --- a/yaksh/templatetags/custom_filters.py +++ b/yaksh/templatetags/custom_filters.py @@ -214,7 +214,7 @@ def get_lesson_views(course_id, lesson_id): @register.simple_tag -def get_dict_value(dictionary, key): - return dictionary.get(key, None) +def get_percent_value(dictionary, key, total): + return round((dictionary.get(str(key), 0)/total)*100) diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 89d209e..8973d9f 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -5671,11 +5671,9 @@ class TestShowStatistics(TestCase): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'yaksh/statistics_question.html') self.assertIn(self.question, list(question_stats.keys())) - self.assertSequenceEqual( - list(question_stats.values())[0]['answered'], [1, 1] - ) - self.assertEqual(response.context['attempts'][0], 1) - self.assertEqual(response.context['total'], 1) + q_data = list(question_stats.values())[0] + self.assertSequenceEqual(q_data[0:2], [1, 1]) + self.assertEqual(100, q_data[2]) class TestQuestionPaper(TestCase): diff --git a/yaksh/views.py b/yaksh/views.py index 5b67570..731d781 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -1326,10 +1326,10 @@ def show_statistics(request, questionpaper_id, attempt_number=None, attempt_numbers = AnswerPaper.objects.get_attempt_numbers( questionpaper_id, course_id) quiz = get_object_or_404(QuestionPaper, pk=questionpaper_id).quiz + context = {'quiz': quiz, 'attempts': attempt_numbers, + 'questionpaper_id': questionpaper_id, + 'course_id': course_id} if attempt_number is None: - context = {'quiz': quiz, 'attempts': attempt_numbers, - 'questionpaper_id': questionpaper_id, - 'course_id': course_id} return my_render_to_response( request, 'yaksh/statistics_question.html', context ) @@ -1338,7 +1338,10 @@ def show_statistics(request, questionpaper_id, attempt_number=None, course_id) if not AnswerPaper.objects.has_attempt(questionpaper_id, attempt_number, course_id): - return my_redirect('/exam/manage/') + messages.warning(request, "No answerpapers found") + return my_render_to_response( + request, 'yaksh/statistics_question.html', context + ) question_stats = AnswerPaper.objects.get_question_statistics( questionpaper_id, attempt_number, course_id ) -- cgit