more improvements

This commit is contained in:
Ross
2021-02-04 10:30:56 +00:00
parent b681a27640
commit cd013f2ff3
32 changed files with 247 additions and 324 deletions
+43 -177
View File
@@ -1,3 +1,6 @@
from django.db.models.fields.files import ImageField
from django.db.models.fields.related import ForeignKey
from anatomy.models import Modality
from django.db import models
from django.utils import timezone
import tagulous
@@ -29,32 +32,6 @@ def image_directory_path(instance, filename):
class Abnormality(models.Model):
name = models.CharField(max_length=200,
unique=True,
help_text="Primary abnormality on the film(s)")
def __str__(self):
return self.name
class Meta:
ordering = ('name', )
class Region(models.Model):
name = models.CharField(
max_length=200,
unique=True,
help_text="Region of the abnormality (not including lateralitiy)",
blank=True)
def __str__(self):
return self.name
class Meta:
ordering = ('name', )
class Examination(models.Model):
examination = models.CharField(max_length=200)
@@ -79,39 +56,6 @@ class Condition(tagulous.models.TagModel):
class Sign(tagulous.models.TagModel):
pass
class Answer(models.Model):
question = models.ForeignKey(
"Long", related_name="answers", on_delete=models.CASCADE
)
answer = models.TextField(max_length=500)
answer_compare = models.TextField(max_length=500)
class MarkOptions(models.TextChoices):
UNMARKED = "", _("Unmarked")
INCORRECT = "0", _("Incorrect")
HALF_MARK = "1", _("Half mark")
CORRECT = "2", _("Correct")
status = models.CharField(
max_length=1, choices=MarkOptions.choices, default=MarkOptions.UNMARKED
)
def __str__(self):
return self.answer
def save(self, *args, **kwargs):
self.clean()
return super(Answer, self).save(*args, **kwargs)
def clean(self):
if self.answer:
self.answer = self.answer.strip()
s = self.answer.lower()
s = s.translate(str.maketrans('', '', string.punctuation))
self.answer_compare = s
class Long(models.Model):
#author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
@@ -119,37 +63,6 @@ class Long(models.Model):
question = models.TextField(null=True, blank=True)
feedback = models.TextField(null=True, blank=True)
normal = models.BooleanField(default=False, help_text="Tick if true")
NONE = "NONE"
LEFT = "LEFT"
RIGHT = "RIGHT"
BILATERAL = "BILAT"
LATERALITY_CHOICES = (
(NONE, "None"),
(LEFT, "Left"),
(RIGHT, "Right"),
(BILATERAL, "Bilateral"),
)
abnormality = models.ManyToManyField(
Abnormality,
blank=True,
help_text="The abnormality (laterality and region independent). Used for categorisation but does not affect the answer",
)
region = models.ManyToManyField(
Region,
blank=True,
help_text="Region of the abnormality (laterality independent)")
examination = models.ManyToManyField(
Examination, help_text="Name of the (primary) examination")
laterality = models.CharField(
max_length=20,
choices=LATERALITY_CHOICES,
default=NONE,
help_text="Applies to the answer, not the examination")
condition = models.CharField(max_length=255, blank=True)
#condition = tagulous.models.TagField(
# to=Condition,
# blank=True,
@@ -161,6 +74,14 @@ class Long(models.Model):
#sign = tagulous.models.TagField(
# to=Sign, blank=True, help_text='Radiological signs in the question')
# Model answers
model_observations = models.TextField(null=True, blank=True)
model_interpretation = models.TextField(null=True, blank=True)
model_principle_diagnosis = models.TextField(null=True, blank=True)
model_differential_diagnosis = models.TextField(null=True, blank=True)
model_further_management = models.TextField(null=True, blank=True)
DEFAULT_SITE_ID = 1
site = models.ManyToManyField(
Site,
@@ -193,91 +114,23 @@ class Long(models.Model):
authors = ", ".join([i.username for i in self.author.all()])
return authors
def get_regions(self):
"""Returns a comma seperated text list of regions"""
regions = ", ".join([i.name for i in self.region.all()])
return regions
def get_abnormalities(self):
"""Returns a comma seperated text list of regions"""
abnormalities = ", ".join([i.name for i in self.abnormality.all()])
return abnormalities
def get_examinations(self):
"""Returns a comma seperated text list of regions"""
examinations = ", ".join([i.examination for i in self.examination.all()])
return examinations
def __str__(self):
n = "Normal"
if not self.normal:
#n = self.answers.first()
n = "{} / {}".format(self.abnormality.first(), self.region.first())
exams = self.get_examinations()
lat = ""
if self.laterality != "NONE":
lat = self.laterality
return "{} / {} {}".format(exams, lat, n)
def GetPrimaryAnswer(self):
if len(self.answers.all()) > 0:
return self.answers.all().first().answer
elif self.normal:
return "Normal"
else:
return "None yet..."
def GetExams(self):
e = self.exams.all().values_list("name", flat=True)
exams = ", ".join(e)
return exams
def GetUnmarkedAnswersString(self):
unmarked_answers = self.GetUnmarkedAnswers()
if not unmarked_answers:
return "No answers to mark"
return format_html(
"<span class='warn'>{} answer unmarked:</span> {}".format(
len(unmarked_answers), ", ".join(unmarked_answers)
)
)
def GetUnmarkedAnswers(self):
# If normal no answers to mark
if self.normal:
return []
user_answers = set(
[i.answer_compare for i in self.cid_user_answers.all() if i.normal == False]
)
unmarked_answers = user_answers - self.GetMarkedAnswers()
return unmarked_answers
def GetUnmarkedAnswerCount(self):
return len(self.GetUnmarkedAnswers())
def GetMarkedAnswers(self):
return set(
[
i.answer_compare
for i in self.answers.all()
if i.status != i.MarkOptions.UNMARKED
]
)
correct_answers = set(
[i.answer.get_compare_string() for i in self.answers.all()]
)
half_mark_answers = set(
[i.answer.get_compare_string() for i in self.half_mark_answers.all()]
)
incorrect_answers = set(
[i.answer.get_compare_string() for i in self.incorrect_answers.all()]
)
marked_answers = correct_answers | half_mark_answers | incorrect_answers
return marked_answers
def GetImages(self, feedback=False):
qs = self.images.all()
@@ -294,24 +147,34 @@ class Long(models.Model):
#def GetNonFeedbackQuestionImages(self):
#return self.GetImages()
class LongImage(models.Model):
long = models.ForeignKey(Long,
related_name="images",
on_delete=models.CASCADE)
class LongSeriesImage(models.Model):
image = models.ImageField(upload_to=image_directory_path, storage=image_storage)
position = models.IntegerField(default=0)
series = models.ForeignKey("LongSeries", related_name="series", on_delete=models.SET_NULL, null=True)
feedback_image = models.BooleanField(default=False)
class LongSeries(models.Model):
modality = models.ForeignKey(Modality, related_name="series_modality", on_delete=models.SET_NULL, null=True)
examination = models.ForeignKey(
Examination, help_text="Name of the examination", on_delete=models.SET_NULL, null=True)
long = models.ForeignKey("Long", related_name="long", on_delete=models.SET_NULL, null=True)
def image_tag(self):
if self.image:
return mark_safe(
'<img src="{}" class="admin-long-image" /><span class="admin-long-image-info">Click and hold to zoom<span>'
.format(self.image.url))
else:
return ""
image_tag.short_description = 'Image'
#class LongImage(models.Model):
# long = models.ForeignKey(Long,
# related_name="images",
# on_delete=models.CASCADE)
# image = models.ImageField(upload_to=image_directory_path, storage=image_storage)
#
# feedback_image = models.BooleanField(default=False)
#
# def image_tag(self):
# if self.image:
# return mark_safe(
# '<img src="{}" class="admin-long-image" /><span class="admin-long-image-info">Click and hold to zoom<span>'
# .format(self.image.url))
# else:
# return ""
#
# image_tag.short_description = 'Image'
class Note(models.Model):
@@ -395,11 +258,14 @@ class CidUserAnswer(models.Model):
Long, related_name="cid_user_answers", on_delete=models.CASCADE
)
# For longs the answer can be normal in which case the below field is true
normal = models.BooleanField(default=False)
answer = models.TextField(max_length=500, blank=True)
answer_compare = models.TextField(max_length=500, blank=True)
# Answers
answer_observations = models.TextField(null=True, blank=True)
answer_interpretation = models.TextField(null=True, blank=True)
answer_principle_diagnosis = models.TextField(null=True, blank=True)
answer_differential_diagnosis = models.TextField(null=True, blank=True)
answer_further_management = models.TextField(null=True, blank=True)
cid = models.BigIntegerField(blank=True, null=True, help_text="Candidate ID (limitied by BigIntegerField size)")