diff options
Diffstat (limited to 'testapp/exam')
-rw-r--r-- | testapp/exam/forms.py | 29 | ||||
-rw-r--r-- | testapp/exam/models.py | 62 | ||||
-rw-r--r-- | testapp/exam/tests.py | 25 | ||||
-rw-r--r-- | testapp/exam/views.py | 15 |
4 files changed, 109 insertions, 22 deletions
diff --git a/testapp/exam/forms.py b/testapp/exam/forms.py index 7c66944..c96ac7e 100644 --- a/testapp/exam/forms.py +++ b/testapp/exam/forms.py @@ -12,7 +12,7 @@ from taggit_autocomplete_modified import settings from string import letters, punctuation, digits import datetime -LANGUAGES = ( +languages = ( ("select", "Select"), ("python", "Python"), ("bash", "Bash"), @@ -22,7 +22,7 @@ LANGUAGES = ( ("scilab", "Scilab"), ) -QUESTION_TYPES = ( +question_types = ( ("select", "Select"), ("mcq", "Multiple Choice"), ("code", "Code"), @@ -31,7 +31,6 @@ QUESTION_TYPES = ( UNAME_CHARS = letters + "._" + digits PWD_CHARS = letters + punctuation + digits - class UserRegisterForm(forms.Form): """A Class to create new form for User's Registration. It has the various fields and functions required to register @@ -127,23 +126,39 @@ class QuizForm(forms.Form): """Creates a form to add or edit a Quiz. It has the related fields and functions required.""" + def __init__(self, *args, **kwargs): + super(QuizForm, self).__init__(*args, **kwargs) + quizzes = [('', 'Select a prerequisite quiz')] + quizzes = quizzes + \ + list(Quiz.objects.values_list('id','description')) + self.fields['prerequisite'] = forms.CharField(required=False, + widget=forms.Select(choices=quizzes)) + start_date = forms.DateField(initial=datetime.date.today) - duration = forms.IntegerField() + duration = forms.IntegerField(help_text='Will be taken in minutes') active = forms.BooleanField(required=False) description = forms.CharField(max_length=256, widget=forms.Textarea\ (attrs={'cols': 20, 'rows': 1})) + pass_criteria = forms.FloatField(initial=40, + help_text='Will be taken as percentage') + language = forms.CharField(widget=forms.Select(choices=languages)) def save(self): start_date = self.cleaned_data["start_date"] duration = self.cleaned_data["duration"] active = self.cleaned_data['active'] description = self.cleaned_data["description"] - + pass_criteria = self.cleaned_data["pass_criteria"] + language = self.cleaned_data["language"] + prerequisite = self.cleaned_data["prerequisite"] new_quiz = Quiz() new_quiz.start_date = start_date new_quiz.duration = duration new_quiz.active = active new_quiz.description = description + new_quiz.pass_criteria = pass_criteria + new_quiz.language = language + new_quiz.prerequisite_id = prerequisite new_quiz.save() @@ -161,9 +176,9 @@ class QuestionForm(forms.Form): options = forms.CharField(widget=forms.Textarea\ (attrs={'cols': 40, 'rows': 1}), required=False) language = forms.CharField(max_length=20, widget=forms.Select\ - (choices=LANGUAGES)) + (choices=languages)) type = forms.CharField(max_length=8, widget=forms.Select\ - (choices=QUESTION_TYPES)) + (choices=question_types)) active = forms.BooleanField(required=False) tags = TagField(widget=TagAutocomplete(), required=False) snippet = forms.CharField(widget=forms.Textarea\ diff --git a/testapp/exam/models.py b/testapp/exam/models.py index 42c5d5a..27d2987 100644 --- a/testapp/exam/models.py +++ b/testapp/exam/models.py @@ -16,7 +16,7 @@ class Profile(models.Model): position = models.CharField(max_length=64) -LANGUAGES = ( +languages = ( ("python", "Python"), ("bash", "Bash"), ("C", "C Language"), @@ -26,7 +26,7 @@ LANGUAGES = ( ) -QUESTION_TYPES = ( +question_types = ( ("mcq", "Multiple Choice"), ("code", "Code"), ) @@ -53,10 +53,10 @@ class Question(models.Model): # The language for question. language = models.CharField(max_length=24, - choices=LANGUAGES) + choices=languages) # The type of question. - type = models.CharField(max_length=24, choices=QUESTION_TYPES) + type = models.CharField(max_length=24, choices=question_types) # Is this question active or not. If it is inactive it will not be used # when creating a QuestionPaper. @@ -115,6 +115,15 @@ class Quiz(models.Model): # Description of quiz. description = models.CharField(max_length=256) + # Mininum passing percentage condition. + pass_criteria = models.FloatField("Passing percentage", default=40) + + # List of prerequisite quizzes to be passed to take this quiz + prerequisite = models.ForeignKey("Quiz", null=True) + + # Programming language for a quiz + language = models.CharField(max_length=20, choices=languages) + class Meta: verbose_name_plural = "Quizzes" @@ -137,11 +146,14 @@ class QuestionPaper(models.Model): # Questions that will be fetched randomly from the Question Set. random_questions = models.ManyToManyField("QuestionSet") + # Option to shuffle questions, each time a new question paper is created. + shuffle_questions = models.BooleanField(default=False) + # Total marks for the question paper. total_marks = models.FloatField() def update_total_marks(self): - """ Returns the total marks for the Question Paper""" + """ Updates the total marks for the Question Paper""" marks = 0.0 questions = self.fixed_questions.all() for question in questions: @@ -149,7 +161,6 @@ class QuestionPaper(models.Model): for question_set in self.random_questions.all(): marks += question_set.marks * question_set.num_questions self.total_marks = marks - return None def _get_questions_for_answerpaper(self): """ Returns fixed and random questions for the answer paper""" @@ -167,8 +178,9 @@ class QuestionPaper(models.Model): + datetime.timedelta(minutes=self.quiz.duration) ans_paper.question_paper = self questions = self._get_questions_for_answerpaper() - question_ids = [str(x.id) for x in questions] - shuffle(questions) + question_ids = [str(x.id) for x in questions] + if self.shuffle_questions: + shuffle(question_ids) ans_paper.questions = "|".join(question_ids) ans_paper.save() return ans_paper @@ -230,6 +242,15 @@ class AnswerPaper(models.Model): # Teacher comments on the question paper. comments = models.TextField() + # Total marks earned by the student in this paper. + marks_obtained = models.FloatField(null=True, default=None) + + # Marks percent scored by the user + percent = models.FloatField(null=True, default=None) + + # Result of the quiz, True if student passes the exam. + passed = models.NullBooleanField() + def current_question(self): """Returns the current active question to display.""" qs = self.questions.split('|') @@ -298,9 +319,28 @@ class AnswerPaper(models.Model): answered = ', '.join(sorted(qa)) return answered if answered else 'None' - def get_marks_obtained(self): - """Returns the total marks earned by student for this paper.""" - return sum([x.marks for x in self.answers.filter(marks__gt=0.0)]) + def update_marks_obtained(self): + """Updates the total marks earned by student for this paper.""" + marks = sum([x.marks for x in self.answers.filter(marks__gt=0.0)]) + self.marks_obtained = marks + + def update_percent(self): + """Updates the percent gained by the student for this paper.""" + total_marks = self.question_paper.total_marks + if self.marks_obtained is not None: + percent = self.marks_obtained/self.question_paper.total_marks*100 + self.percent = round(percent, 2) + + def update_passed(self): + """ + Checks whether student passed or failed, as per the quiz + passing criteria. + """ + if self.percent is not None: + if self.percent >= self.question_paper.quiz.pass_criteria: + self.passed = True + else: + self.passed = False def get_question_answers(self): """ diff --git a/testapp/exam/tests.py b/testapp/exam/tests.py index b2ba36f..d76e4f8 100644 --- a/testapp/exam/tests.py +++ b/testapp/exam/tests.py @@ -21,7 +21,8 @@ def setUpModule(): # create a quiz Quiz.objects.create(start_date='2014-06-16', duration=30, active=False, - description='demo quiz') + description='demo quiz', pass_criteria=40, + language='Python', prerequisite=None) def tearDownModule(): @@ -86,6 +87,9 @@ class QuizTestCases(unittest.TestCase): self.assertEqual(self.quiz.duration, 30) self.assertTrue(self.quiz.active is False) self.assertEqual(self.quiz.description, 'demo quiz') + self.assertEqual(self.quiz.language, 'Python') + self.assertEqual(self.quiz.pass_criteria, 40) + self.assertEqual(self.quiz.prerequisite, None) ############################################################################### @@ -98,7 +102,8 @@ class QuestionPaperTestCases(unittest.TestCase): # create question paper self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, - total_marks=0.0) + total_marks=0.0, shuffle_questions=True) + # add fixed set of questions to the question paper self.question_paper.fixed_questions.add(self.questions[3], self.questions[5]) @@ -135,6 +140,7 @@ class QuestionPaperTestCases(unittest.TestCase): self.assertEqual(self.question_paper.quiz.description, 'demo quiz') self.assertEqual(list(self.question_paper.fixed_questions.all()), [self.questions[3], self.questions[5]]) + self.assertTrue(self.question_paper.shuffle_questions) def test_update_total_marks(self): """ Test update_total_marks() method of Question Paper""" @@ -257,9 +263,20 @@ class AnswerPaperTestCases(unittest.TestCase): answered_question = self.answerpaper.get_answered_str() self.assertEqual(answered_question, '1') - def test_get_marks_obtained(self): + def test_update_marks_obtained(self): """ Test get_marks_obtained() method of Answer Paper""" - self.assertEqual(self.answerpaper.get_marks_obtained(), 1.0) + self.answerpaper.update_marks_obtained() + self.assertEqual(self.answerpaper.marks_obtained, 1.0) + + def test_update_percent(self): + """ Test update_percent() method of Answerpaper""" + self.answerpaper.update_percent() + self.assertEqual(self.answerpaper.percent, 33.33) + + def test_update_passed(self): + """ Test update_passed method of AnswerPaper""" + self.answerpaper.update_passed() + self.assertFalse(self.answerpaper.passed) def test_get_question_answer(self): """ Test get_question_answer() method of Answer Paper""" diff --git a/testapp/exam/views.py b/testapp/exam/views.py index 7353d82..422e16f 100644 --- a/testapp/exam/views.py +++ b/testapp/exam/views.py @@ -188,6 +188,9 @@ def edit_quiz(request): duration = request.POST.getlist('duration') active = request.POST.getlist('active') description = request.POST.getlist('description') + pass_criteria = request.POST.getlist('pass_criteria') + language = request.POST.getlist('language') + prerequisite = request.POST.getlist('prerequisite') for j, quiz_id in enumerate(quiz_list): quiz = Quiz.objects.get(id=quiz_id) @@ -195,6 +198,9 @@ def edit_quiz(request): quiz.duration = duration[j] quiz.active = active[j] quiz.description = description[j] + quiz.pass_criteria = pass_criteria[j] + quiz.language = language[j] + quiz.prerequisite_id = prerequisite[j] quiz.save() return my_redirect("/exam/manage/showquiz/") @@ -322,6 +328,9 @@ def add_quiz(request, quiz_id=None): d.duration = form['duration'].data d.active = form['active'].data d.description = form['description'].data + d.pass_criteria = form['pass_criteria'].data + d.language = form['language'].data + d.prerequisite_id = form['prerequisite'].data d.save() quiz = Quiz.objects.get(id=quiz_id) return my_redirect("/exam/manage/showquiz") @@ -342,6 +351,9 @@ def add_quiz(request, quiz_id=None): form.initial['duration'] = d.duration form.initial['description'] = d.description form.initial['active'] = d.active + form.initial['pass_criteria'] = d.pass_criteria + form.initial['language'] = d.language + form.initial['prerequisite'] = d.prerequisite_id return my_render_to_response('exam/add_quiz.html', {'form': form}, context_instance=ci) @@ -910,6 +922,9 @@ def show_all_quiz(request): form.initial['duration'] = d.duration form.initial['active'] = d.active form.initial['description'] = d.description + form.initial['pass_criteria'] = d.pass_criteria + form.initial['language'] = d.language + form.initial['prerequisite'] = d.prerequisite_id forms.append(form) return my_render_to_response('exam/edit_quiz.html', {'forms': forms, 'data': data}, |