Skip to content

Commit 82b4f0e

Browse files
Merge pull request #293 from ul-fmf/outcome
Nov način izračuna izidov
2 parents 788fb60 + 615bd1f commit 82b4f0e

File tree

11 files changed

+174
-332
lines changed

11 files changed

+174
-332
lines changed

web/attempts/outcome.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
from dataclasses import dataclass
2+
3+
from django.db.models import Count
4+
from django.utils.translation import gettext_lazy as _
5+
6+
from .models import Attempt
7+
8+
9+
def _group_sizes(queryset, *group_by):
10+
if group_by:
11+
return {
12+
tuple(group): count
13+
for *group, count in queryset.values_list(*group_by).annotate(Count("id"))
14+
}
15+
else:
16+
return {(): queryset.count()}
17+
18+
19+
@dataclass
20+
class Outcome:
21+
valid: int = 0
22+
invalid: int = 0
23+
total: int = 0
24+
25+
def __add__(self, other):
26+
return Outcome(
27+
self.valid + other.valid,
28+
self.invalid + other.invalid,
29+
self.total + other.total,
30+
)
31+
32+
@property
33+
def empty(self):
34+
return self.total - self.valid - self.invalid
35+
36+
@property
37+
def valid_percentage(self):
38+
return int(100 * self.valid / self.total)
39+
40+
@property
41+
def invalid_percentage(self):
42+
return int(100 * self.invalid / self.total)
43+
44+
@property
45+
def empty_percentage(self):
46+
return 100 - self.valid_percentage - self.invalid_percentage
47+
48+
@property
49+
def grade(self):
50+
return min(5, int(5 * self.valid / self.total) + 1)
51+
52+
def summary(self):
53+
valid = f'{self.valid} { _("valid") }'
54+
invalid = f'{self.invalid} { _("invalid") }'
55+
empty = f'{self.empty} { _("empty") }'
56+
return f"{valid} / {invalid} / {empty}"
57+
58+
def percentage_summary(self):
59+
valid = f'{self.valid_percentage}% { _("valid") }'
60+
invalid = f'{self.invalid_percentage}% { _("invalid") }'
61+
empty = f'{self.empty_percentage}% { _("empty") }'
62+
return f"{valid} / {invalid} / {empty}"
63+
64+
@classmethod
65+
def group_dict(cls, parts, users, parts_group_by, users_group_by):
66+
part_group_sizes = _group_sizes(parts, *parts_group_by)
67+
user_group_sizes = _group_sizes(users, *users_group_by)
68+
outcomes = {}
69+
for part_group, part_group_size in part_group_sizes.items():
70+
for user_group, user_group_size in user_group_sizes.items():
71+
outcomes[part_group + user_group] = cls(
72+
total=part_group_size * user_group_size
73+
)
74+
attempts = Attempt.objects.filter(part__in=parts, user__in=users).distinct()
75+
group_by = [f"part__{g}" for g in parts_group_by] + [
76+
f"user__{g}" for g in users_group_by
77+
]
78+
for (*group, valid), count in _group_sizes(
79+
attempts, *group_by, "valid"
80+
).items():
81+
outcomes[tuple(group)] += cls(valid=count) if valid else cls(invalid=count)
82+
return outcomes

0 commit comments

Comments
 (0)