summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--yaksh/models.py82
-rw-r--r--yaksh/templates/yaksh/monitor.html1
-rw-r--r--yaksh/templates/yaksh/statistics_question.html30
-rw-r--r--yaksh/urls.py4
-rw-r--r--yaksh/views.py26
5 files changed, 143 insertions, 0 deletions
diff --git a/yaksh/models.py b/yaksh/models.py
index 712c455..8415930 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -2,6 +2,7 @@ import datetime
import json
from random import sample, shuffle
from itertools import islice, cycle
+from collections import Counter
from django.db import models
from django.contrib.auth.models import User
from taggit.managers import TaggableManager
@@ -283,6 +284,70 @@ class QuestionSet(models.Model):
###############################################################################
+class AnswerPaperManager(models.Manager):
+ def get_all_questions(self, questionpaper_id, attempt_number,
+ status='completed'):
+ ''' Return a dict of question id as key and count as value'''
+ papers = self.filter(question_paper_id=questionpaper_id,
+ attempt_number=attempt_number, status=status)
+ questions = list()
+ for paper in papers:
+ questions += paper.get_questions()
+ return Counter(map(int, questions))
+
+ def get_all_questions_answered(self, questionpaper_id, attempt_number,
+ status='completed'):
+ ''' Return a dict of answered question id as key and count as value'''
+ papers = self.filter(question_paper_id=questionpaper_id,
+ attempt_number=attempt_number, status=status)
+ questions_answered = list()
+ for paper in papers:
+ for question in filter(None, paper.get_questions_answered()):
+ if paper.is_answer_correct(question):
+ questions_answered.append(question)
+ return Counter(map(int, questions_answered))
+
+ def get_attempt_numbers(self, questionpaper_id, status='completed'):
+ ''' Return list of attempt numbers'''
+ attempt_numbers = self.filter(
+ question_paper_id=questionpaper_id, status=status
+ ).values_list('attempt_number', flat=True).distinct()
+ return attempt_numbers
+
+ def has_attempt(self, questionpaper_id, attempt_number, status='completed'):
+ ''' Whether question paper is attempted'''
+ return self.filter(question_paper_id=questionpaper_id,
+ attempt_number=attempt_number, status=status).exists()
+
+ def get_count(self, questionpaper_id, attempt_number, 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).count()
+
+ def get_question_statistics(self, questionpaper_id, attempt_number,
+ 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'''
+ question_stats = {}
+ questions_answered = self.get_all_questions_answered(questionpaper_id,
+ attempt_number)
+ questions = self.get_all_questions(questionpaper_id, attempt_number)
+ all_questions = Question.objects.filter(
+ id__in=set(questions)
+ ).order_by('type')
+ for question in all_questions:
+ if question.id in questions_answered:
+ question_stats[question] = [questions_answered[question.id],
+ questions[question.id]]
+ else:
+ question_stats[question] = [0, questions[question.id]]
+ return question_stats
+
+
+###############################################################################
class AnswerPaper(models.Model):
"""A answer paper for a student -- one per student typically.
"""
@@ -330,6 +395,8 @@ class AnswerPaper(models.Model):
status = models.CharField(max_length=20, choices=test_status,\
default='inprogress')
+ objects = AnswerPaperManager()
+
def current_question(self):
"""Returns the current active question to display."""
qu = self.get_unanswered_questions()
@@ -448,6 +515,19 @@ class AnswerPaper(models.Model):
q_a[question] = [answer]
return q_a
+ def get_questions(self):
+ ''' Return a list of questions'''
+ return self.questions.split('|')
+
+ def get_questions_answered(self):
+ ''' Return a list of questions answered'''
+ return self.questions_answered.split('|')
+
+ def is_answer_correct(self, question_id):
+ ''' Return marks of a question answered'''
+ return self.answers.filter(question_id=question_id,
+ correct=True).exists()
+
def __unicode__(self):
u = self.user
return u'Question paper for {0} {1}'.format(u.first_name, u.last_name)
@@ -475,3 +555,5 @@ class TestCase(models.Model):
# Test case Expected answer in list form
expected_answer = models.TextField(blank=True, null = True)
+
+
diff --git a/yaksh/templates/yaksh/monitor.html b/yaksh/templates/yaksh/monitor.html
index ecb8b42..cb14ba5 100644
--- a/yaksh/templates/yaksh/monitor.html
+++ b/yaksh/templates/yaksh/monitor.html
@@ -39,6 +39,7 @@
{% if papers %}
<p>Number of papers: {{ papers|length }} </p>
+<p><a href="{{URL_ROOT}}/exam/manage/statistics/question/{{papers.0.question_paper.id}}">Question Statisitics</a></p>
<table border="1" cellpadding="3">
<tr>
<th> Name </th>
diff --git a/yaksh/templates/yaksh/statistics_question.html b/yaksh/templates/yaksh/statistics_question.html
new file mode 100644
index 0000000..a63844f
--- /dev/null
+++ b/yaksh/templates/yaksh/statistics_question.html
@@ -0,0 +1,30 @@
+{% extends "manage.html" %}
+
+{% block title %} Statistics {% endblock title %}
+
+{% block css %}
+<link rel="stylesheet" href="{{ URL_ROOT }}/static/yaksh/css/question_quiz.css" type="text/css" />
+{% endblock %}
+{% block subtitle %}
+Statistics for {{quiz.description}}
+{% endblock %}
+{% block manage %}
+<div class="row">
+ <div class="span2">
+{% for attempt in attempts %}
+ <p><a href="{{URL_ROOT}}/exam/manage/statistics/question/{{questionpaper_id}}/{{attempt}}">Attempt {{ attempt }}</a></p>
+ {% endfor %}
+</div>
+<div class="span10">
+{% if question_stats %}
+ <p><b>Total number of participants: {{ total }}</b></p>
+ <table class="bordered-table zebra-striped">
+ <tr><th>Question</th><th>Type</th><th>Total</th><th>Answered</th></tr>
+ {% for question, value in question_stats.items %}
+ <tr><td>{{ question.summary }}</td><td>{{ question.type }}</td><td>{{value.1}}</td><td>{{ value.0 }} ({% widthratio value.0 value.1 100 %}%)</td></tr>
+ {% endfor %}
+ </table>
+ {% endif %}
+ </div>
+</div>
+{% endblock %}
diff --git a/yaksh/urls.py b/yaksh/urls.py
index 61222b8..e6c2e15 100644
--- a/yaksh/urls.py
+++ b/yaksh/urls.py
@@ -50,6 +50,10 @@ urlpatterns = patterns('yaksh.views',
url(r'^manage/designquestionpaper/manual$', 'manual_questionpaper'),
url(r'^manage/designquestionpaper/manual/(?P<questionpaper_id>\d+)/$',\
'manual_questionpaper'),
+ url(r'^manage/statistics/question/(?P<questionpaper_id>\d+)/$',
+ 'show_statistics'),
+ url(r'^manage/statistics/question/(?P<questionpaper_id>\d+)/(?P<attempt_number>\d+)/$',
+ 'show_statistics'),
url(r'^ajax/questionpaper/(?P<query>.+)/$', 'ajax_questionpaper'),
url(r'^ajax/questions/filter/$', 'ajax_questions_filter'),
diff --git a/yaksh/views.py b/yaksh/views.py
index 755b33b..6558427 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -1166,6 +1166,32 @@ def complete(request, reason=None, attempt_num=None, questionpaper_id=None):
@login_required
+def show_statistics(request, questionpaper_id, attempt_number=None):
+ user = request.user
+ if not is_moderator(user):
+ raise Http404('You are not allowed to view this page')
+ attempt_numbers = AnswerPaper.objects.get_attempt_numbers(questionpaper_id)
+ quiz = get_object_or_404(QuestionPaper, pk=questionpaper_id).quiz
+ if attempt_number is None:
+ context = {'quiz': quiz, 'attempts': attempt_numbers,
+ 'questionpaper_id': questionpaper_id}
+ return my_render_to_response('yaksh/statistics_question.html', context,
+ context_instance=RequestContext(request))
+ total_attempt = AnswerPaper.objects.get_count(questionpaper_id,
+ attempt_number)
+ if not AnswerPaper.objects.has_attempt(questionpaper_id, attempt_number):
+ return my_redirect('/exam/manage/')
+ question_stats = AnswerPaper.objects.get_question_statistics(
+ questionpaper_id, attempt_number
+ )
+ context = {'question_stats': question_stats, 'quiz': quiz,
+ 'questionpaper_id': questionpaper_id,
+ 'attempts': attempt_numbers, 'total': total_attempt}
+ return my_render_to_response('yaksh/statistics_question.html', context,
+ context_instance=RequestContext(request))
+
+
+@login_required
def monitor(request, questionpaper_id=None):
"""Monitor the progress of the papers taken so far."""