improve stats handling

This commit is contained in:
Ross
2024-01-08 22:46:46 +00:00
parent 9d05e5d34e
commit d6f1de2036
10 changed files with 166 additions and 11 deletions
+5 -2
View File
@@ -1,6 +1,9 @@
# Current target
- User management
- SQUASH MIGRATIONS
- Exam dates
- Exam groups (and compare scores)
- Exam results reviewing
# Ongoing
@@ -0,0 +1,18 @@
# Generated by Django 4.1.4 on 2024-01-08 22:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('anatomy', '0004_exam_candidates_only_alter_exam_active_and_more'),
]
operations = [
migrations.AddField(
model_name='exam',
name='stats_graph',
field=models.TextField(default=0),
),
]
+29 -8
View File
@@ -759,7 +759,7 @@ class ExamBase(ExamCollectionGenericBase):
stats_max_possible = models.FloatField(default=0)
# stats_graph = models.TextField(default=0)
stats_graph = models.TextField(default=0)
user_scores = models.JSONField(default=dict)
@@ -868,29 +868,50 @@ class ExamBase(ExamCollectionGenericBase):
stats = self.get_exam_stats(name=False)
exam_text.append(f"Stats\n{'-'*len('Stats')}\n{stats}")
rapids_extra = ""
if self.app_name == "rapids":
exam_text.append(f"Answers breakdown: {callstate}")
rapids_extra = f"Answers breakdown: {callstate}"
exam_text.append(rapids_extra)
msg = "\n\n".join(exam_text)
return msg
html_msg = f"""
<p>Candidate: {user.first_name} [{user.email}]</p>
<h2>{exam_name}</h2>
<h3>Results</h3>
Score: {user_score} / {int(self.stats_max_possible)} ({percentage})
<h3>Stats</h3>
{stats}<br/>
<a href="{settings.REMOTE_URL}{reverse("{}:exam_stats".format(self.app_name), args=(self.pk,))}">View all stats (including graph) here</a>
"""
if self.app_name == "rapids":
html_msg =f"{html_msg}<br/>{rapids_extra}"
return msg, html_msg
def email_user_results(self, user, resend=False, additional_emails=None):
# if self.results_email_sent and not resend:
# return False, "Already sent."
# Get a list of taken exams
msg = self.generate_user_report(user)
msg, html_msg = self.generate_user_report(user)
if not user.email:
return [False, "User has no email"]
emails = [user.email]
supervisor_email = user.userprofile.supervisor.email
extra = ""
if supervisor_email:
if user.userprofile.supervisor is not None:
supervisor_email = user.userprofile.supervisor.email
emails.append(supervisor_email)
else:
extra = "No supervisor"
if additional_emails is not None:
emails.extend(additional_emails)
@@ -902,14 +923,14 @@ class ExamBase(ExamCollectionGenericBase):
"no-reply@penracourses.org.uk",
emails,
fail_silently=False,
# html_message=html_msg,
html_message=html_msg,
)
except SMTPException as e:
return [False, e]
# self.results_email_sent = True
# self.save()
return [True, ""]
return [True, extra]
class ExamUserStatus(models.Model):
+5
View File
@@ -225,6 +225,11 @@ def generic_exam_urls(generic_exam_view: GenericExamViews):
generic_exam_view.exam_scores_all,
name="exam_scores_all",
),
path(
"exam/<int:exam_id>/stats",
generic_exam_view.exam_stats,
name="exam_stats",
),
path(
"exam/<int:pk>/scores/refresh",
generic_exam_view.exam_scores_refresh,
+17 -1
View File
@@ -2162,7 +2162,7 @@ class ExamViews(View, LoginRequiredMixin):
exam.stats_min = min(user_scores_list)
exam.stats_max = max(user_scores_list)
# exam.stats_graph = fig_html
exam.stats_graph = fig_html
user_data = {}
for u in cids:
@@ -2225,6 +2225,22 @@ class ExamViews(View, LoginRequiredMixin):
template_variables,
)
def exam_stats(self, request, exam_id):
exam = get_object_or_404(self.Exam, pk=exam_id)
if not exam.exam_mode:
raise Http404("Packet not in exam mode")
template_variables = {
"exam": exam
}
return render(
request,
"exam_stats.html",
template_variables,
)
class GenericViewBase:
def __init__(self, app_name, QuestionObject, UserAnswerObject, ExamObject):
+18
View File
@@ -0,0 +1,18 @@
# Generated by Django 4.1.4 on 2024-01-08 22:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('longs', '0013_alter_longseriesimage_image_blake3_hash'),
]
operations = [
migrations.AddField(
model_name='exam',
name='stats_graph',
field=models.TextField(default=0),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 4.1.4 on 2024-01-08 22:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('physics', '0002_exam_candidates_only_alter_exam_active_and_more'),
]
operations = [
migrations.AddField(
model_name='exam',
name='stats_graph',
field=models.TextField(default=0),
),
]
@@ -0,0 +1,18 @@
# Generated by Django 4.1.4 on 2024-01-08 22:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rapids', '0002_exam_candidates_only_alter_exam_active_and_more'),
]
operations = [
migrations.AddField(
model_name='exam',
name='stats_graph',
field=models.TextField(default=0),
),
]
+18
View File
@@ -0,0 +1,18 @@
# Generated by Django 4.1.4 on 2024-01-08 22:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sbas', '0003_alter_useranswer_answer'),
]
operations = [
migrations.AddField(
model_name='exam',
name='stats_graph',
field=models.TextField(default=0),
),
]
+20
View File
@@ -0,0 +1,20 @@
{% extends 'base.html' %}
{% block content %}
<h2>{{exam.name}}</h2>
{% if exam.stats_candidates < 4 %}
Not enough data points...
{% else %}
<div id="stats-plot">{{exam.stats_graph|safe}}</div>
Questions: <span id="question-number">{{question_number}}</span><br />
Available marks: {{exam_stats_max_possible}}<br />
Mean: {{exam.stats_mean}}, Median {{exam.stats_median}}, Mode {{exam.stats_mode}}<br />
Top score: {{exam.stats_max}}
<p class="small-gray">Note: scores < 10% of the total score are excluded from these statistics
{% endif %}
{% endblock %}