From 8747c671d87418be83c8c6b9849e2962cdbb0715 Mon Sep 17 00:00:00 2001 From: adityacp Date: Sat, 24 Oct 2020 16:42:10 +0530 Subject: Improve lesson statistics --- yaksh/code_server.py | 5 +- yaksh/models.py | 44 +++++++++-- yaksh/static/yaksh/js/show_toc.js | 2 +- yaksh/templates/base.html | 7 +- yaksh/templates/manage.html | 7 ++ yaksh/templates/user.html | 8 +- yaksh/templates/yaksh/show_lesson_statistics.html | 51 +++++++++---- yaksh/templates/yaksh/show_video.html | 93 ++++++++++++----------- yaksh/templatetags/custom_filters.py | 9 ++- yaksh/views.py | 15 +++- 10 files changed, 164 insertions(+), 77 deletions(-) (limited to 'yaksh') diff --git a/yaksh/code_server.py b/yaksh/code_server.py index 4feb7fd..60f966f 100644 --- a/yaksh/code_server.py +++ b/yaksh/code_server.py @@ -17,7 +17,10 @@ import json from multiprocessing import Process, Queue, Manager import os from os.path import dirname, abspath -import pwd +try: + import pwd +except ImportError: + pass import sys import time diff --git a/yaksh/models.py b/yaksh/models.py index da2327c..932e38c 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -25,6 +25,7 @@ import zipfile import tempfile from textwrap import dedent from ast import literal_eval +import pandas as pd # Django Imports from django.db import models @@ -2812,19 +2813,50 @@ class TOCManager(models.Manager): data = {} for toc in contents: data[toc] = LessonQuizAnswer.objects.filter( - toc_id=toc.id).values_list("toc_id").distinct().count() + toc_id=toc.id).values_list( + "student_id", flat=True).distinct().count() return data def get_question_stats(self, toc_id): answers = LessonQuizAnswer.objects.get_queryset().filter( toc_id=toc_id).order_by('id') - question = answers.first().toc.content_object - answers = answers.values( - "student__first_name", "student__last_name", "student__email", - "student_id", "toc_id" - ).distinct() + question = TableOfContents.objects.get(id=toc_id).content_object + if answers.exists(): + answers = answers.values( + "student__first_name", "student__last_name", "student__email", + "student_id", "toc_id" + ) + df = pd.DataFrame(answers) + answers = df.drop_duplicates().to_dict(orient='records') return question, answers + def get_per_tc_ans(self, toc_id, question_type, is_percent=True): + answers = LessonQuizAnswer.objects.filter(toc_id=toc_id).values( + "student_id", "answer__answer" + ).order_by("id") + data = None + if answers.exists(): + df = pd.DataFrame(answers) + grp = df.groupby(["student_id"]).tail(1) + total_count = grp.count().answer__answer + data = grp.groupby(["answer__answer"]).count().to_dict().get( + "student_id") + if question_type == "mcc": + tc_ids = [] + mydata = {} + for i in data.keys(): + tc_ids.extend(literal_eval(i)) + for j in tc_ids: + if j not in mydata: + mydata[j] = 1 + else: + mydata[j] +=1 + data = mydata.copy() + if is_percent: + for key, value in data.items(): + data[key] = (value/total_count)*100 + return data, total_count + def get_answer(self, toc_id, user_id): submission = LessonQuizAnswer.objects.filter( toc_id=toc_id, student_id=user_id).last() diff --git a/yaksh/static/yaksh/js/show_toc.js b/yaksh/static/yaksh/js/show_toc.js index 7d9b68e..a2507d0 100644 --- a/yaksh/static/yaksh/js/show_toc.js +++ b/yaksh/static/yaksh/js/show_toc.js @@ -13,7 +13,7 @@ $(document).ready(function() { }); }, max_height: 400, - height: 400, + height: 200, plugins: "image code link", convert_urls: false }); diff --git a/yaksh/templates/base.html b/yaksh/templates/base.html index 2cc607c..a108f8c 100644 --- a/yaksh/templates/base.html +++ b/yaksh/templates/base.html @@ -54,14 +54,9 @@ - + {% block script %} {% endblock %} diff --git a/yaksh/templates/manage.html b/yaksh/templates/manage.html index 53d5c72..047f784 100644 --- a/yaksh/templates/manage.html +++ b/yaksh/templates/manage.html @@ -65,6 +65,13 @@ + {% endblock %} {% block content %} diff --git a/yaksh/templates/user.html b/yaksh/templates/user.html index 4e3974b..7211d5c 100644 --- a/yaksh/templates/user.html +++ b/yaksh/templates/user.html @@ -43,7 +43,13 @@ {% endblock %} - + {% block content %} {% block main %} diff --git a/yaksh/templates/yaksh/show_lesson_statistics.html b/yaksh/templates/yaksh/show_lesson_statistics.html index 2bcdd2d..31261f3 100644 --- a/yaksh/templates/yaksh/show_lesson_statistics.html +++ b/yaksh/templates/yaksh/show_lesson_statistics.html @@ -102,6 +102,19 @@ {% endif %} {{tc.options}} + {% if per_tc_ans %} + {% get_tc_percent tc.id per_tc_ans as percent %} +
+ {% if percent %} +
+ {{percent}}% +
+ {% else %} + 0% + {% endif %} +
+ {% endif %} {% elif question.type == "integer" %} Answer: {{tc.correct}} @@ -116,33 +129,43 @@
+ Total Submissions: {{total_count}} +

+ {% if question.type != 'mcq' and question.type != 'mcc' %} +
+ +

+ {% endif %} {% include "yaksh/paginator.html" %} - - + {% for data in objects.object_list %} - + {% get_answers data.toc_id data.student_id as user_answer %} - {% endfor %}
Sr No. Student Name EmailLatest AnswerStatusLatest Submission
{{forloop.counter}}{{ forloop.counter0|add:objects.start_index }} {{data.student__first_name}} {{data.student__last_name}} {{data.student__email}}{{ user_answer.0 }} - {% if user_answer.1 %} - - Correct - - {% else %} - - Incorrect - - {% endif %} -
diff --git a/yaksh/templates/yaksh/show_video.html b/yaksh/templates/yaksh/show_video.html index 6e3cabb..58c7e04 100644 --- a/yaksh/templates/yaksh/show_video.html +++ b/yaksh/templates/yaksh/show_video.html @@ -140,9 +140,9 @@ {% else %}
+ {% if lesson.video_path %}
- {% if lesson.video_path %} {% with lesson.video_path|video_name as video %} {% if video.1 == "others" %}
+ {% if toc %}
-
- -
-
- - {% for content in toc %} - {% with content.get_toc_text as toc_name %} - - - - - - - - {% endwith %} - {% empty %} -
- No Table of contents added -
- {% endfor %} -
- - {{ toc_name }} - - - {{content.get_content_display}} - - {{content.time}} -
+
+ +
+
+ + {% for content in toc %} + {% with content.get_toc_text as toc_name %} + + + + + + + + {% endwith %} + {% empty %} +
+ No Table of contents added +
+ {% endfor %} +
+ + {{ toc_name }} + + + {{content.get_content_display}} + + {{content.time}} +
+
-
+ {% endif %} + {% endif %}
- - Next  - -

Lesson Description

@@ -227,23 +225,28 @@
+
+ + Next  + +
{% endif %} {% if state == 'lesson' %} -
- Add comment: +
+ Comments:
{% csrf_token %} - {{form}} + {{form.as_p}}
- +
{% endif %}
{% if comments %} {% for comment in comments %} -
+
diff --git a/yaksh/templatetags/custom_filters.py b/yaksh/templatetags/custom_filters.py index 57ec7dd..a3cd3f1 100644 --- a/yaksh/templatetags/custom_filters.py +++ b/yaksh/templatetags/custom_filters.py @@ -3,6 +3,7 @@ from django.template.defaultfilters import stringfilter from django.forms.fields import CheckboxInput from ast import literal_eval import os +import pandas as pd try: from itertools import zip_longest except ImportError: @@ -192,4 +193,10 @@ def has_lesson_video(lesson_id): status = True if lesson.first().video_path else False else: status = False - return status \ No newline at end of file + return status + + +@register.simple_tag +def get_tc_percent(tc_id, data): + return data.get(str(tc_id), 0) + diff --git a/yaksh/views.py b/yaksh/views.py index 69a7414..e01bf86 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -4025,8 +4025,19 @@ def lesson_statistics(request, course_id, lesson_id, toc_id=None): context['course_id'] = course_id if toc_id: per_que_data = TableOfContents.objects.get_question_stats(toc_id) - paginator = Paginator(per_que_data[1], 50) - context['question'] = per_que_data[0] + question = per_que_data[0] + answers = per_que_data[1] + is_percent_reqd = ( + True if question.type == "mcq" or question.type == "mcc" + else False + ) + per_tc_ans, total_count = TableOfContents.objects.get_per_tc_ans( + toc_id, question.type, is_percent_reqd + ) + context['per_tc_ans'] = per_tc_ans + context['total_count'] = total_count + paginator = Paginator(answers, 50) + context['question'] = question page = request.GET.get('page') per_que_data = paginator.get_page(page) context['is_que_data'] = True -- cgit From 54740d2e9b3e9c67521074380730cc949dfaefb0 Mon Sep 17 00:00:00 2001 From: adityacp Date: Mon, 26 Oct 2020 09:52:39 +0530 Subject: Improve tests for lesson statistics --- yaksh/test_views.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'yaksh') diff --git a/yaksh/test_views.py b/yaksh/test_views.py index e7bbd91..2db217f 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -8195,6 +8195,29 @@ class TestLessonContents(TestCase): 'integertestcase_set-0-type': 'integertestcase', 'integertestcase_set-0-correct': "1"} ) + self.client.post( + reverse('yaksh:add_marker_quiz', + kwargs={"content_type": '3', + "course_id": self.user1_course1.id, + "lesson_id": self.lesson1.id}), + data={'timer': '00:00:00', 'summary': 'Mcc_Lesson_stats', + 'description': 'My lesson question description', + 'language': 'other', 'type': 'mcc', 'topic': 'test', + 'points': '1', 'form-TOTAL_FORMS': 2, + 'form-MAX_NUM_FORMS': '', + 'form-INITIAL_FORMS': 0, + 'mcqtestcase_set-TOTAL_FORMS': 2, + 'mcqtestcase_set-INITIAL_FORMS': 0, + 'mcqtestcase_set-MIN_NUM_FORMS': 0, + 'mcqtestcase_set-MAX_NUM_FORMS': 0, + 'mcqtestcase_set-0-type': 'mcqtestcase', + 'mcqtestcase_set-0-options': "1", + 'mcqtestcase_set-0-correct': True, + 'mcqtestcase_set-1-type': 'mcqtestcase', + 'mcqtestcase_set-1-options': "2", + 'mcqtestcase_set-1-correct': False + } + ) que = Question.objects.filter(summary="My_Lesson_question") single_que = que.first() @@ -8247,6 +8270,43 @@ class TestLessonContents(TestCase): ) self.assertEqual(student_info.get("student_id"), self.student.id) + # Test for mcc lesson question statistics + # Given + que = Question.objects.filter(summary="Mcc_Lesson_stats") + + single_que = que.first() + toc = TableOfContents.objects.get( + course_id=self.user1_course1.id, lesson_id=self.lesson1.id, + object_id=single_que.id + ) + self.client.logout() + + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.post( + reverse('yaksh:submit_marker_quiz', + kwargs={"course_id": self.user1_course1.id, + "toc_id": toc.id}), + data={'answer': [str(i.id) for i in single_que.get_test_cases()]} + ) + self.client.logout() + + # Then + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:lesson_statistics', + kwargs={"course_id": self.user1_course1.id, + "lesson_id": self.lesson1.id, + "toc_id": toc.id}) + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(student_info.get("student_id"), self.student.id) + def test_multiple_lesson_question_types(self): self.client.login( username=self.user1.username, -- cgit From 167b53a673630c4243c5d82a5966797213a5fa28 Mon Sep 17 00:00:00 2001 From: adityacp Date: Mon, 2 Nov 2020 15:45:29 +0530 Subject: Minor UI fixes --- yaksh/templates/yaksh/add_lesson.html | 18 +++++++++++------- yaksh/templates/yaksh/show_toc.html | 2 +- yaksh/templates/yaksh/show_video.html | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) (limited to 'yaksh') diff --git a/yaksh/templates/yaksh/add_lesson.html b/yaksh/templates/yaksh/add_lesson.html index 329a8e0..d8ce09c 100644 --- a/yaksh/templates/yaksh/add_lesson.html +++ b/yaksh/templates/yaksh/add_lesson.html @@ -89,9 +89,11 @@ {{lesson_form.video_path}}
Video File: - - {{lesson_form.video_file.help_text}} - +
+ + {{lesson_form.video_file.help_text}} + +
{{lesson_form.video_file}}
@@ -210,10 +212,12 @@
{% endwith %} {% else %} -
- - Add a Video Path or Upload a video file to setup lesson contents - +
+
+ + Add a Video Path or Upload a video file to setup lesson contents + +
{% endif %}
diff --git a/yaksh/templates/yaksh/show_toc.html b/yaksh/templates/yaksh/show_toc.html index 92ea0cd..104815f 100644 --- a/yaksh/templates/yaksh/show_toc.html +++ b/yaksh/templates/yaksh/show_toc.html @@ -16,7 +16,7 @@

{% endif %} - +
{% for toc in contents %} {% with toc.get_toc_text as toc_name %} diff --git a/yaksh/templates/yaksh/show_video.html b/yaksh/templates/yaksh/show_video.html index 58c7e04..9061e70 100644 --- a/yaksh/templates/yaksh/show_video.html +++ b/yaksh/templates/yaksh/show_video.html @@ -184,7 +184,7 @@ {% endwith %} {% empty %} -
+
No Table of contents added
{% endfor %} @@ -229,10 +229,10 @@ Next  -
{% endif %} {% if state == 'lesson' %}
+
Comments:
-- cgit