245 lines
7.6 KiB
Python
245 lines
7.6 KiB
Python
from django.db import models
|
|
from django.utils import timezone
|
|
|
|
from django.core.files.storage import FileSystemStorage
|
|
from django.conf import settings
|
|
|
|
image_storage = FileSystemStorage(
|
|
# Physical file location ROOT
|
|
location=u"{0}/anatomy/".format(settings.MEDIA_ROOT),
|
|
# Url for file
|
|
base_url=u"{0}anatomy/".format(settings.MEDIA_URL),
|
|
)
|
|
|
|
|
|
def image_directory_path(instance, filename):
|
|
# file will be uploaded to MEDIA_ROOT/anatomy/picture/<filename>
|
|
return u"picture/{0}".format(filename)
|
|
|
|
|
|
class Examination(models.Model):
|
|
examination = models.CharField(max_length=200)
|
|
|
|
def __str__(self):
|
|
return self.examination
|
|
|
|
|
|
class BodyPart(models.Model):
|
|
bodypart = models.CharField(max_length=200)
|
|
|
|
def __str__(self):
|
|
return self.bodypart
|
|
|
|
|
|
class Structure(models.Model):
|
|
bodypart = models.CharField(max_length=200)
|
|
|
|
def __str__(self):
|
|
return self.bodypart
|
|
|
|
|
|
class Modality(models.Model):
|
|
modality = models.CharField(max_length=200)
|
|
|
|
def __str__(self):
|
|
return self.modality
|
|
|
|
|
|
class QuestionType(models.Model):
|
|
text = models.CharField(max_length=400)
|
|
|
|
def __str__(self):
|
|
return self.text
|
|
|
|
|
|
class AnatomyQuestion(models.Model):
|
|
# author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
|
|
# image = models.ImageField()
|
|
# feedback = models.TextField(null=True)
|
|
question_type = models.ForeignKey(QuestionType,
|
|
on_delete=models.SET_NULL,
|
|
null=True)
|
|
|
|
image = models.ImageField(upload_to=image_directory_path,
|
|
storage=image_storage)
|
|
|
|
description = models.CharField(
|
|
max_length=400,
|
|
help_text=
|
|
"Short description of the image e.g. 'Sagittal CT Chest, Abdomen & Pelvis', will be displayed as the title."
|
|
)
|
|
|
|
examination = models.ForeignKey(Examination,
|
|
on_delete=models.SET_NULL,
|
|
null=True, blank=True)
|
|
modality = models.ForeignKey(Modality,
|
|
on_delete=models.SET_NULL,
|
|
null=True, help_text="Modality of the image")
|
|
body_part = models.ForeignKey(BodyPart,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True)
|
|
structure = models.ForeignKey(Structure,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True)
|
|
created_date = models.DateTimeField(default=timezone.now)
|
|
|
|
def __str__(self):
|
|
# Get first answer
|
|
a = self.answers.all().first()
|
|
|
|
# Get associated exams
|
|
e = self.exams.all().values_list("name", flat=True)
|
|
exams = ", ".join(e)
|
|
|
|
if a is None:
|
|
return "({})".format(exams)
|
|
else:
|
|
return "{} ({}) [{}, {}]".format(a.answer, exams, self.modality,
|
|
self.structure)
|
|
|
|
def GetUnmarkedAnswersString(self):
|
|
unmarked_answers = self.GetUnmarkedAnswers()
|
|
|
|
if not unmarked_answers:
|
|
return "No answers to mark"
|
|
return "{} answer unmarked: {}".format(len(unmarked_answers),
|
|
", ".join(unmarked_answers))
|
|
|
|
def GetUnmarkedAnswers(self):
|
|
user_answers = set([i.answer for i in self.user_answers.all()])
|
|
unmarked_answers = user_answers - self.GetMarkedAnswers()
|
|
|
|
return unmarked_answers
|
|
|
|
def GetMarkedAnswers(self):
|
|
correct_answers = set([i.answer for i in self.answers.all()])
|
|
half_mark_answers = set(
|
|
[i.answer for i in self.half_mark_answers.all()])
|
|
incorrect_answers = set(
|
|
[i.answer for i in self.incorrect_answers.all()])
|
|
|
|
marked_answers = correct_answers | half_mark_answers | incorrect_answers
|
|
return marked_answers
|
|
|
|
|
|
class Answers(models.Model):
|
|
question = models.ForeignKey(AnatomyQuestion,
|
|
related_name="answers",
|
|
on_delete=models.CASCADE)
|
|
answer = models.CharField(max_length=500)
|
|
|
|
def __str__(self):
|
|
return self.answer
|
|
|
|
def clean(self):
|
|
if self.answer:
|
|
self.answer.strip()
|
|
|
|
|
|
class HalfMarkAnswers(models.Model):
|
|
question = models.ForeignKey(AnatomyQuestion,
|
|
related_name="half_mark_answers",
|
|
on_delete=models.CASCADE)
|
|
answer = models.CharField(max_length=500)
|
|
|
|
def __str__(self):
|
|
return self.answer
|
|
|
|
def clean(self):
|
|
if self.answer:
|
|
self.answer.strip()
|
|
|
|
|
|
class IncorrectAnswers(models.Model):
|
|
question = models.ForeignKey(AnatomyQuestion,
|
|
related_name="incorrect_answers",
|
|
on_delete=models.CASCADE)
|
|
answer = models.CharField(max_length=500)
|
|
|
|
def __str__(self):
|
|
return self.answer
|
|
|
|
def clean(self):
|
|
if self.answer:
|
|
self.answer.strip()
|
|
|
|
|
|
class Exam(models.Model):
|
|
name = models.CharField(max_length=200)
|
|
exam_questions = models.ManyToManyField(AnatomyQuestion,
|
|
related_name="exams")
|
|
|
|
active = models.BooleanField(help_text="If an exam should be available", default=True)
|
|
|
|
def __str__(self):
|
|
return self.name
|
|
|
|
|
|
class UserAnswer(models.Model):
|
|
question = models.ForeignKey(AnatomyQuestion,
|
|
related_name="user_answers",
|
|
on_delete=models.CASCADE)
|
|
answer = models.CharField(max_length=500, blank=True)
|
|
user = models.ForeignKey(settings.AUTH_USER_MODEL,
|
|
null=True,
|
|
blank=True,
|
|
on_delete=models.SET_NULL)
|
|
|
|
cid = models.IntegerField(blank=True, null=True)
|
|
|
|
# Each user answer is associated with a particular exam
|
|
exam = models.ForeignKey(Exam,
|
|
related_name="exam",
|
|
on_delete=models.CASCADE,
|
|
null=True)
|
|
|
|
flagged = models.BooleanField(default=False)
|
|
|
|
created = models.DateTimeField(auto_now_add=True)
|
|
updated = models.DateTimeField(auto_now=True)
|
|
|
|
def __str__(self):
|
|
try:
|
|
exam = self.exam
|
|
except (Exam.DoesNotExist, KeyError) as e:
|
|
exam = "None"
|
|
return "{}/{}/{}: {}".format(exam, self.cid, self.question.id,
|
|
self.answer)
|
|
|
|
def clean(self):
|
|
if self.answer:
|
|
self.answer.strip()
|
|
|
|
|
|
class CidUserAnswer(models.Model):
|
|
"""User answers by candidate"""
|
|
question = models.ForeignKey(AnatomyQuestion,
|
|
related_name="cid_user_answers",
|
|
on_delete=models.CASCADE)
|
|
answer = models.CharField(max_length=500, blank=True)
|
|
|
|
cid = models.IntegerField(blank=True, null=True)
|
|
|
|
# Each user answer is associated with a particular exam
|
|
exam = models.ForeignKey(Exam,
|
|
related_name="cid_user_answers",
|
|
on_delete=models.CASCADE,
|
|
null=True)
|
|
|
|
created = models.DateTimeField(auto_now_add=True)
|
|
updated = models.DateTimeField(auto_now=True)
|
|
|
|
def __str__(self):
|
|
try:
|
|
exam = self.exam
|
|
except (Exam.DoesNotExist, KeyError) as e:
|
|
exam = "None"
|
|
return "{}/{}/{}: {}".format(exam, self.cid, self.question.id,
|
|
self.answer)
|
|
|
|
def clean(self):
|
|
if self.answer:
|
|
self.answer.strip()
|