From 19a9a27747a530f93deb47cb25351fe2c2e122d1 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 8 Jul 2024 13:14:11 +0100 Subject: [PATCH] tidy up some longs related stuff --- anatomy/views.py | 4 +- generic/models.py | 1 - generic/views.py | 37 ++++++++--- longs/forms.py | 7 ++- ...answermarks_candidate_feedback_and_more.py | 22 +++++++ longs/models.py | 16 ++--- longs/templates/longs/exam_scores.html | 2 + longs/templates/longs/exam_scores_user.html | 27 ++++++-- longs/templates/longs/mark_answer.html | 3 +- longs/tests/test_longs_exams.py | 4 +- longs/views.py | 61 ++++++++++++++----- 11 files changed, 140 insertions(+), 44 deletions(-) create mode 100644 longs/migrations/0025_remove_answermarks_candidate_feedback_and_more.py diff --git a/anatomy/views.py b/anatomy/views.py index 136191b6..ff01e1fd 100644 --- a/anatomy/views.py +++ b/anatomy/views.py @@ -89,9 +89,9 @@ class AuthorOrCheckerRequiredMixin(object): @register.filter -def get_item(dictionary, key): +def get_item(dictionary, key, default=None): if dictionary is None: - return None + return default return dictionary.get(key) diff --git a/generic/models.py b/generic/models.py index c6a685cf..d34a69f8 100644 --- a/generic/models.py +++ b/generic/models.py @@ -870,7 +870,6 @@ class ExamBase(ExamOrCollectionGenericBase): abstract = True def __str__(self): - print("TESTING") if self.start_date and self.start_date is not None: print(f"Start date: {self.start_date:%d %B %Y}") return f"{self.name} ({self.start_date:%d %B %Y})" diff --git a/generic/views.py b/generic/views.py index 780ddd98..c8c628a4 100644 --- a/generic/views.py +++ b/generic/views.py @@ -1860,8 +1860,6 @@ class ExamViews(View, LoginRequiredMixin): return self.exam_question_json_unbased(request, pk, sk, cid, passcode) def exam_question_json_unbased(self, request, pk, sk, cid=None, passcode=None): - print("TESTING") - print("**************************") question = get_object_or_404(self.Question, pk=sk) exam = get_object_or_404(self.Exam, pk=pk) @@ -1951,7 +1949,7 @@ class ExamViews(View, LoginRequiredMixin): ).first() # user_answer = cid_user_answers_q_map[q] - print("QUSETION", q) + feedback = None if not user_answer or user_answer is None: # skip if no answer score, text = q.get_unanswered_mark_and_text() @@ -1962,8 +1960,10 @@ class ExamViews(View, LoginRequiredMixin): else: ans = user_answer.get_answer() answer_score = user_answer.get_answer_score() - print("ans", ans) - print("ans score", answer_score) + + if self.app_name == "longs": + feedback = user_answer.candidate_feedback + match self.app_name: case "sbas": @@ -1998,7 +1998,11 @@ class ExamViews(View, LoginRequiredMixin): answer_score = 0 answers.append(ans) answers_marks.append(answer_score) - answers_and_marks.append((ans, answer_score, correct_answer)) + + if self.app_name == "longs": + answers_and_marks.append((ans, answer_score, correct_answer, feedback)) + else: + answers_and_marks.append((ans, answer_score, correct_answer)) print(answers_marks) @@ -2072,7 +2076,7 @@ class ExamViews(View, LoginRequiredMixin): # user_answers_and_marks = defaultdict(list) user_answers_marks = defaultdict(list) - user_answers = defaultdict(list) + #user_answers = defaultdict(list) # user_names = {} # cid_passcodes = {} @@ -2146,7 +2150,7 @@ class ExamViews(View, LoginRequiredMixin): if answer_score == "unmarked": index = exam.get_question_index(q) unmarked.add(index) - user_answers[cid].append(ans) + #user_answers[cid].append(ans) user_answers_marks[cid].append(answer_score) if self.app_name == "rapids": @@ -2159,10 +2163,27 @@ class ExamViews(View, LoginRequiredMixin): zipped_ans_scores = zip(ans, answer_score) by_question[q][cid] = zipped_ans_scores + + + user_scores = {} user_scores_normalised = {} user_answer_count = {} for user in user_answers_marks: + + # For longs we have a default score of 3 (not 0) if unanswered + # so we need to check for those + if self.app_name == "longs": + for question in questions: + if question not in by_question: + continue + + if user not in by_question[question]: + #print("NOT in") + by_question[question][user] = ("Not answered", 3.0) + user_answers_marks[user].append(3.0) + + if self.app_name in ("rapids", "anatomy", "sbas", "longs"): user_scores[user] = sum( [i for i in user_answers_marks[user] if i != "unmarked"] diff --git a/longs/forms.py b/longs/forms.py index 83dc05d5..b5d544f1 100755 --- a/longs/forms.py +++ b/longs/forms.py @@ -51,13 +51,16 @@ class LongAnswerForm(ModelForm): class MarkLongQuestionSingleForm(ModelForm): class Meta: model = UserAnswer - fields = ["score"] + fields = ["score", "candidate_feedback"] + widgets = { + "candidate_feedback": Textarea(attrs={"rows": 3}), + } class MarkLongQuestionDoubleForm(ModelForm): class Meta: model = AnswerMarks - fields = ["score", "mark_reason", "candidate_feedback"] + fields = ["score", "mark_reason"] class ExaminationForm(ModelForm): diff --git a/longs/migrations/0025_remove_answermarks_candidate_feedback_and_more.py b/longs/migrations/0025_remove_answermarks_candidate_feedback_and_more.py new file mode 100644 index 00000000..74405930 --- /dev/null +++ b/longs/migrations/0025_remove_answermarks_candidate_feedback_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 5.0.2 on 2024-07-08 11:49 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('longs', '0024_alter_exam_end_date_alter_exam_exam_results_emailed_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='answermarks', + name='candidate_feedback', + ), + migrations.AddField( + model_name='useranswer', + name='candidate_feedback', + field=models.TextField(blank=True, help_text='Feedback for the candidate', null=True), + ), + ] diff --git a/longs/models.py b/longs/models.py index a4e4f418..d74423fc 100644 --- a/longs/models.py +++ b/longs/models.py @@ -328,12 +328,13 @@ class Long(QuestionBase): return url - def get_unanswered_mark_and_text(self) -> tuple[int, tuple[str, str, str, str, str]]: + def get_unanswered_mark_and_text(self) -> tuple[int, str]: """ Long cases are receive a mark between 4 and 8 - Therefore unmarked = 4 + This has changed to a 3 if unanswered + Therefore unmarked = 3 """ - return (4, ("Not answered",) * 5) + return (3, ("Not answered",) * 5) # def GetNonFeedbackQuestionImages(self): # return self.get_images() @@ -612,6 +613,7 @@ class UserAnswer(UserAnswerBase): class ScoreOptions(models.TextChoices): UNMARKED = "", _("Unmarked") + #UNANSWERED = "3", _("Unanswered") FOUR = "4", _("4") FOUR_HALF = "4.5", _("4.5") FIVE = "5", _("5") @@ -630,6 +632,10 @@ class UserAnswer(UserAnswerBase): help_text="The final score for the candidate", ) + candidate_feedback = models.TextField( + null=True, blank=True, help_text="Feedback for the candidate" + ) + # mark = models.ManyToManyField( # "AnswerMarks", related_name="user_answer", blank=True # ) @@ -752,10 +758,6 @@ class AnswerMarks(models.Model): help_text="Reason for the given mark - not visible to candidates", ) - candidate_feedback = models.TextField( - null=True, blank=True, help_text="Feedback for the candidate" - ) - marker = models.ForeignKey( settings.AUTH_USER_MODEL, related_name="marker", on_delete=models.CASCADE ) diff --git a/longs/templates/longs/exam_scores.html b/longs/templates/longs/exam_scores.html index b389e1d7..32e8f331 100644 --- a/longs/templates/longs/exam_scores.html +++ b/longs/templates/longs/exam_scores.html @@ -2,6 +2,8 @@ {% extends 'generic/exam_scores_base.html' %} {% block table_answers %} +aoeu +eu {% for question in questions %} Question {{forloop.counter}} diff --git a/longs/templates/longs/exam_scores_user.html b/longs/templates/longs/exam_scores_user.html index 0a393643..d65d5469 100644 --- a/longs/templates/longs/exam_scores_user.html +++ b/longs/templates/longs/exam_scores_user.html @@ -16,10 +16,14 @@
{% comment %}

Answers

{% endcomment %}
{% endblock %} +{% block css %} + +{% endblock css %} {% block js %}