from django.contrib.contenttypes.fields import GenericRelation from django.db import models from django.utils import timezone from django.core.files.storage import FileSystemStorage from django.conf import settings from django.utils.html import format_html from django.urls import reverse from django.utils.translation import gettext_lazy as _ from sortedm2m.fields import SortedManyToManyField from generic.models import CidUser, CidUserGroup, ExamBase, ExamUserStatus, QuestionBase, QuestionNote, UserAnswerBase, UserUserGroup import reversion class Category(models.Model): category = models.CharField(max_length=200) def __str__(self): return self.category class Question(QuestionBase): stem = models.TextField( blank=False, help_text="Stem of the question", ) answer_help_text = "Answer (check for true, uncheck for false)" a = models.TextField( blank=False, help_text="The question text", ) a_answer = models.BooleanField(help_text=answer_help_text, default=True) a_feedback = models.TextField( blank=True, help_text="Feedback for answer", ) b = models.TextField( blank=False, help_text="The question text", ) b_answer = models.BooleanField(help_text=answer_help_text, default=True) b_feedback = models.TextField( blank=True, help_text="Feedback for answer", ) c = models.TextField( blank=False, help_text="The question text", ) c_answer = models.BooleanField(help_text=answer_help_text, default=True) c_feedback = models.TextField( blank=True, help_text="Feedback for answer", ) d = models.TextField( blank=False, help_text="The question text", ) d_answer = models.BooleanField(help_text=answer_help_text, default=True) d_feedback = models.TextField( blank=True, help_text="Feedback for answer", ) e = models.TextField( blank=False, help_text="The question text", ) e_answer = models.BooleanField(help_text=answer_help_text, default=True) e_feedback = models.TextField( blank=True, help_text="Feedback for answer", ) author = models.ManyToManyField( settings.AUTH_USER_MODEL, blank=True, help_text="Author(s) of question", related_name="physics_authored_questions", ) category = models.ForeignKey( Category, on_delete=models.SET_NULL, null=True, blank=True ) #notes = GenericRelation(QuestionNote) def __str__(self): return self.stem def clean(self): if self.a: self.a = self.a.strip() if self.b: self.b = self.b.strip() if self.c: self.c = self.c.strip() if self.d: self.d = self.d.strip() if self.e: self.e = self.e.strip() def get_absolute_url(self): return reverse("physics:question_detail", kwargs={"pk": self.pk}) def get_answers(self): return [ self.a_answer, self.b_answer, self.c_answer, self.d_answer, self.e_answer, ] def get_answers_js(self): return str(self.get_answers()).lower() def get_questions(self): return [self.a, self.b, self.c, self.d, self.e] def get_unanswered_mark_and_text(self) -> tuple[int, tuple[str, str, str, str, str]]: """ returns score, tuple[answers] """ return ((0,) * 5, ("Not answered",) * 5) #@reversion.register class Exam(ExamBase): app_name = "physics" exam_questions = SortedManyToManyField(Question, related_name="exams", blank="true") time_limit = models.IntegerField( help_text="Exam time limit (in seconds)", blank=True, null=True, ) recreate_json = None author = models.ManyToManyField( settings.AUTH_USER_MODEL, blank=True, help_text="Author of exam", related_name="physics_exam_author", ) valid_cid_users = models.ManyToManyField( CidUser, blank=True, related_name="physics_exams" ) valid_user_users = models.ManyToManyField( settings.AUTH_USER_MODEL, blank=True, related_name="user_physics_exams" ) cid_user_groups = models.ManyToManyField( CidUserGroup, blank=True, help_text="These groups define which candidates are able to be added to the exams/collection.", related_name="physics_cid_user_groups" ) user_user_groups = models.ManyToManyField( UserUserGroup, blank=True, help_text="These groups define which candidates are able to be added to the exams/collection.", related_name="physics_user_user_groups" ) exam_user_status = GenericRelation(ExamUserStatus) def get_take_url(self): return reverse("physics:exam_start", kwargs={"pk": self.pk}) @reversion.register class UserAnswer(UserAnswerBase): """User answers by candidate""" app_name = "physics" question = models.ForeignKey( Question, related_name="cid_user_answers", on_delete=models.CASCADE ) a = models.BooleanField(blank=False) b = models.BooleanField(blank=False) c = models.BooleanField(blank=False) d = models.BooleanField(blank=False) e = models.BooleanField(blank=False) user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True, related_name="user_physics_user_answers", ) # Each user answer is associated with a particular exam exam = models.ForeignKey( Exam, related_name="cid_user_answers", on_delete=models.CASCADE, null=True ) def get_answers(self): return (self.a, self.b, self.c, self.d, self.e) def get_answer(self): return self.get_answers() def get_answer_string(self): return [str(i) for i in (self.a, self.b, self.c, self.d, self.e)] def get_answer_score(self): q = self.question if self.a == q.a_answer: score_a = 1 else: score_a = 0 if self.b == q.b_answer: score_b = 1 else: score_b = 0 if self.c == q.c_answer: score_c = 1 else: score_c = 0 if self.d == q.d_answer: score_d = 1 else: score_d = 0 if self.e == q.e_answer: score_e = 1 else: score_e = 0 return (score_a, score_b, score_c, score_d, score_e)