Skip to content

Commit 89b48b7

Browse files
calculate score for student report
1 parent caa6f76 commit 89b48b7

File tree

6 files changed

+132
-3
lines changed

6 files changed

+132
-3
lines changed

classroom/business/all/student_report.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,70 @@ def __init__(self, classroom, student):
44
self.student = student
55

66
def make(self):
7-
return {'success': True}
7+
reports = []
8+
exercises = self.get_exercises()
9+
10+
for exercise in exercises:
11+
report = self.new_report(exercise)
12+
submission = self.get_submission(exercise)
13+
14+
if submission:
15+
report['submitted'] = True
16+
questions = exercise.questions.all()
17+
answers = submission.answers.all()
18+
19+
report['passage_1'] = self.calculate_score(questions, answers, 1)
20+
report['passage_2'] = self.calculate_score(questions, answers, 2)
21+
report['passage_3'] = self.calculate_score(questions, answers, 3)
22+
report['band_score'] = (
23+
self.calculate_band(report['passage_1']) +
24+
self.calculate_band(report['passage_2']) +
25+
self.calculate_band(report['passage_3'])
26+
)
27+
28+
reports.append(report)
29+
30+
return reports
31+
32+
@staticmethod
33+
def new_report(exercise):
34+
return {
35+
'exercise': exercise.identifier,
36+
'passage_1': 0,
37+
'passage_2': 0,
38+
'passage_3': 0,
39+
'total': 0,
40+
'band_score': 1,
41+
'submitted': False,
42+
}
43+
44+
def get_exercises(self):
45+
return self.classroom.reading_exercises.all().prefetch_related('questions')
46+
47+
def get_submission(self, exercise):
48+
return exercise.submissions.filter(submitter=self.student).prefetch_related('answers').first()
49+
50+
def calculate_score(self, questions, answers, passage):
51+
questions = filter(
52+
lambda question: getattr(question, f'is_passage_{passage}')(),
53+
questions
54+
)
55+
56+
score = 0
57+
for question in questions:
58+
answer = self.get_answer(answers, question)
59+
is_correct = question.check_answer(answer.content)
60+
if is_correct:
61+
score += 1
62+
63+
return score
64+
65+
@staticmethod
66+
def calculate_band(score):
67+
pass
68+
69+
@staticmethod
70+
def get_answer(answers, question):
71+
for answer in answers:
72+
if answer.question_number == question.number:
73+
return answer
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 3.2.7 on 2021-10-06 16:39
2+
3+
from django.conf import settings
4+
from django.db import migrations
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
11+
('classroom', '0012_auto_20211006_2118'),
12+
]
13+
14+
operations = [
15+
migrations.AlterUniqueTogether(
16+
name='readingsubmission',
17+
unique_together={('exercise', 'submitter')},
18+
),
19+
]

classroom/models/abstracts/question.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import re
2+
13
from django.db import models
24
from django.utils.translation import gettext_lazy as _
35

@@ -39,17 +41,45 @@ def set_default_choices(self):
3941
elif not self.is_multiple_choice():
4042
self.choices = ''
4143

44+
def is_multiple_choice(self):
45+
return self.question_type == self.Types.MULTIPLE_CHOICE
46+
4247
def is_true_false(self):
4348
return self.question_type == self.Types.TRUE_FALSE
4449

4550
def is_yes_no(self):
4651
return self.question_type == self.Types.YES_NO
4752

48-
def is_multiple_choice(self):
49-
return self.question_type == self.Types.MULTIPLE_CHOICE
53+
def is_fill_blank(self):
54+
return self.question_type == self.Types.FILL_BLANK
5055

5156
def get_answers_content(self):
5257
answers = []
5358
for answer in self.answers.all():
5459
answers.append(answer.content)
5560
return answers
61+
62+
def check_answer(self, answer):
63+
possible_answers = self.answers.all()
64+
65+
if self.is_fill_blank():
66+
answer = f' {answer} ' # Add 2 spaces to both side to help with regex matching
67+
68+
for correct_answer in possible_answers:
69+
regex = correct_answer
70+
if regex.startswith('('):
71+
regex = r'(?:' + regex[1:]
72+
73+
regex = regex.replace(' (', r'(?:\s?')\
74+
.replace(')', r')?')
75+
regex = r'\s*' + regex + r'\s*'
76+
77+
match = re.match(regex, answer)
78+
if match:
79+
match_str = match.group(0)
80+
if match_str == answer:
81+
return True
82+
83+
return False
84+
else:
85+
return answer in possible_answers

classroom/models/reading_question.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,12 @@ def create_answers(self, answers):
2626
def replace_answers(self, answers):
2727
self.answers.all().delete()
2828
self.create_answers(answers)
29+
30+
def is_passage_1(self):
31+
return self.passage == 1
32+
33+
def is_passage_2(self):
34+
return self.passage == 2
35+
36+
def is_passage_3(self):
37+
return self.passage == 3

classroom/models/reading_submission.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class ReadingSubmission(models.Model):
1313

1414
class Meta:
1515
ordering = ['exercise', 'submitter', 'submit_datetime']
16+
unique_together = ['exercise', 'submitter']
1617

1718
def get_answers(self):
1819
return self.answers.all().values('question_number', 'content')

classroom/serializers/exercise.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ def save(self, **kwargs):
2929
class _SubmitAnswerListSerializer(serializers.ListSerializer):
3030
def save(self, exercise=None):
3131
student = self.context['request'].user
32+
if exercise.submissions.filter(submitter=student).exists():
33+
raise serializers.ValidationError(
34+
_('You already submitted answers for this exercise.')
35+
)
3236
submission = self._create_submission(student, exercise)
3337
self._create_submission_answers(submission)
3438

0 commit comments

Comments
 (0)