diff --git a/longs/models.py b/longs/models.py
index c7fc639d..f1373745 100644
--- a/longs/models.py
+++ b/longs/models.py
@@ -205,6 +205,7 @@ class Long(models.Model):
#"feedback_image": [],
#"annotations": [str(q.image_annotations)],
"type": "long",
+ "cached": False,
}
return exam_question
@@ -393,14 +394,10 @@ class LongSeries(models.Model):
else:
skipcount = skipcount + 1
- print("skipped, no SliceLocation: {}".format(skipcount))
+ print("skipped, no {}: {}".format(field, skipcount))
# ensure they are in the correct order
slices = sorted(slices, key=lambda s: s[field].value)
- #if field == "SliceLocation":
- # slices = sorted(slices, key=lambda s: s.SliceLocation)
- #elif field == "InstanceNumber":
- # slices = sorted(slices, key=lambda s: s.InstanceNumber)
#print(slices)
@@ -632,12 +629,6 @@ class CidUserAnswer(models.Model):
ans = ans.strip()
- # def get_compare_string(self):
- # # strip here should be unneccasry (providing clean is now working)
- # s = self.answer.lower().strip()
- # s = s.translate(str.maketrans('', '', string.punctuation))
- # return s
-
def is_marked(self):
if self.score == "":
return False
@@ -645,4 +636,6 @@ class CidUserAnswer(models.Model):
return True
def get_answer_score(self):
+ if self.score == "":
+ return ""
return float(self.score)
diff --git a/longs/templates/longs/exam_scores_user.html b/longs/templates/longs/exam_scores_user.html
index 86936e20..0fca8f71 100644
--- a/longs/templates/longs/exam_scores_user.html
+++ b/longs/templates/longs/exam_scores_user.html
@@ -4,13 +4,28 @@
Exam: {{ exam.name }}
Candidate: {{ cid }}
- Answers:
+ Scores:
{% for score in answers_marks %}
Question {{forloop.counter}}
{{ans}} ({{score}})
{% endfor %}
Total mark: {{ total_score }} / {{max_score}}
+
+
Answers
+
{% for a,b,c,d,e in answer_text %}
+ Question {{forloop.counter}}
+
+ Observation{{a}}
+ Interpretation{{b}}
+ Principle Diagnosis{{c}}
+ Differential Diagnosis{{d}}
+ Management{{e}}
+
+ {% endfor %}
+
+
+
diff --git a/longs/templates/longs/long_series_viewer.html b/longs/templates/longs/long_series_viewer.html
index 425599a9..9617b76f 100755
--- a/longs/templates/longs/long_series_viewer.html
+++ b/longs/templates/longs/long_series_viewer.html
@@ -17,6 +17,7 @@ This series is not associated with any cases.
{% for image in series.images.all %}
diff --git a/longs/urls.py b/longs/urls.py
index 3ed91a4e..f331d6ce 100755
--- a/longs/urls.py
+++ b/longs/urls.py
@@ -13,6 +13,7 @@ urlpatterns = [
path("series/
", views.long_series_detail, name="long_series_detail"),
path("series//order_dicom", views.long_series_order_dicom, name="long_series_order_dicom"),
path("series//order_dicom_instance", views.long_series_order_dicom_instance, name="long_series_order_dicom_instance"),
+ path("series//order_dicom_SeriesInstanceUID", views.long_series_order_dicom_SeriesInstanceUID, name="long_series_order_dicom_SeriesInstanceUID"),
path("series//order_upload_filename", views.long_series_order_upload_filename, name="long_series_order_upload_filename"),
path("series//delete", views.LongSeriesDelete.as_view(), name="long_series_delete"),
# path("unchecked/", views.unchecked_list, name="unchecked_list"),
diff --git a/longs/views.py b/longs/views.py
index 24e73b7e..bb82ac6f 100755
--- a/longs/views.py
+++ b/longs/views.py
@@ -889,21 +889,27 @@ def exam_scores_cid_user(request, pk, sk):
#answers_and_marks = []
answers_marks = []
#answers = []
+ answer_text = []
for q in questions:
# Get user answer
user_answer = q.cid_user_answers.filter(cid=cid).first()
+
+
if not user_answer or user_answer is None:
# skip if no answer
#answers_marks.append("")
#answers.append("")
answer_score = 4
#ans = "Not answered"
+ answer_text.append((("Not answered"),("Not answered"),("Not answered"),("Not answered"),("Not answered")))
else:
answer_score = user_answer.get_answer_score()
+ answer_text.append((user_answer.answer_observations, user_answer.answer_interpretation, user_answer.answer_principle_diagnosis, user_answer.answer_differential_diagnosis, user_answer.answer_management))
+
if not exam.publish_results:
answer_score = 0
#answers.append(ans)
@@ -931,6 +937,7 @@ def exam_scores_cid_user(request, pk, sk):
"answers_marks": answers_marks,
"total_score": total_score,
"max_score": max_score,
+ "answer_text": answer_text
#"answers_and_marks": answers_and_marks,
},
)
@@ -955,6 +962,16 @@ def long_series_order_dicom_instance(request, pk):
return redirect("longs:long_series_detail", pk=pk)
+@login_required
+def long_series_order_dicom_SeriesInstanceUID(request, pk):
+ series = get_object_or_404(LongSeries, pk=pk)
+ try:
+ series.order_by_dicom("SeriesInstanceUID")
+ except:
+ return HttpResponse('Series does not appear to contain dicoms (or field SeriesInstanceUID) ')
+
+ return redirect("longs:long_series_detail", pk=pk)
+
@login_required
def long_series_order_upload_filename(request, pk):
series = get_object_or_404(LongSeries, pk=pk)
@@ -986,6 +1003,9 @@ def question_json(request, pk):
cache.set("{}_question_json_{}".format("longs", pk), question_json, 3600)
+ question.recreate_json = False
+ question.save()
+
return JsonResponse(question_json)
@login_required
diff --git a/rapids/admin.py b/rapids/admin.py
index 75d4d0b1..0cf20a6e 100755
--- a/rapids/admin.py
+++ b/rapids/admin.py
@@ -1,5 +1,5 @@
from django.contrib import admin
-from .models import Rapid, RapidImage, Examination, Site, Abnormality, Region, Note, RapidCreationDefault, Answer, Exam
+from .models import Rapid, RapidImage, Examination, Site, Abnormality, Region, Note, RapidCreationDefault, Answer, Exam, CidUserAnswer
import tagulous.admin
@@ -72,3 +72,9 @@ class RapidAdmin(VersionAdmin):
admin.site.register(Rapid, RapidAdmin)
#tagulous.admin.register(Rapid.condition)
+
+class CidUserAnswerAdmin(admin.ModelAdmin):
+ exclude = []
+ readonly_fields = ["created", "updated"]
+
+admin.site.register(CidUserAnswer, CidUserAnswerAdmin)
\ No newline at end of file
diff --git a/rapids/forms.py b/rapids/forms.py
index 41e03f92..dafba32e 100755
--- a/rapids/forms.py
+++ b/rapids/forms.py
@@ -65,13 +65,13 @@ class AbnormalityForm(ModelForm):
class RapidCreationDefaultForm(ModelForm):
class Meta:
model = RapidCreationDefault
- #fields = ["site"]
+ # fields = ["site"]
exclude = ["author"]
class RapidForm(ModelForm):
- exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all(),widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False))
+ # exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all(),widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False))
class Media:
# Django also includes a few javascript files necessary
# for the operation of this form element. You need to
@@ -84,11 +84,6 @@ class RapidForm(ModelForm):
js = ["jsi18n.js", "tesseract.min.js"]
def __init__(self, *args, **kwargs):
- ModelForm.__init__(self, *args, **kwargs)
- super(RapidForm, self).__init__(*args, **kwargs)
- # self.fields['question'].widget.attrs = {'class': 'question-form', 'rows': 10, 'cols': 100}
- # self.fields['feedback'].widget.attrs = {'class': 'feedback-form', 'rows': 10, 'cols': 100}
-
if kwargs.get("instance"):
# We get the 'initial' keyword argument or initialize it
# as a dict if it didn't exist.
@@ -97,6 +92,11 @@ class RapidForm(ModelForm):
# a list of primary key for the selected data.
initial["exams"] = [t.pk for t in kwargs["instance"].exams.all()]
+ ModelForm.__init__(self, *args, **kwargs)
+ super(RapidForm, self).__init__(*args, **kwargs)
+ # self.fields['question'].widget.attrs = {'class': 'question-form', 'rows': 10, 'cols': 100}
+ # self.fields['feedback'].widget.attrs = {'class': 'feedback-form', 'rows': 10, 'cols': 100}
+
self.fields["abnormality"] = ModelMultipleChoiceField(
required=False,
queryset=Abnormality.objects.all(),
@@ -117,7 +117,11 @@ class RapidForm(ModelForm):
self.fields["laterality"] = ChoiceField(
choices=Rapid.LATERALITY_CHOICES, required=False, widget=RadioSelect()
)
-
+ self.fields["exams"] = ModelMultipleChoiceField(
+ required=False,
+ queryset=Exam.objects.all(),
+ widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False),
+ )
def save(self, commit=True):
# Get the unsaved Pizza instance
@@ -152,7 +156,7 @@ class RapidForm(ModelForm):
"region",
"laterality",
"examination",
- #"site",
+ # "site",
"feedback",
]
# fields = ['question', 'feedback', 'subspecialty', 'references']
@@ -185,7 +189,7 @@ AnswerFormSet = inlineformset_factory(
},
exclude=[],
can_delete=True,
- extra=1,
+ extra=0,
max_num=10,
)
diff --git a/rapids/models.py b/rapids/models.py
index 894eac85..a72dc6cd 100644
--- a/rapids/models.py
+++ b/rapids/models.py
@@ -99,7 +99,7 @@ class Answer(models.Model):
self.answer = self.answer.strip()
s = self.answer.lower()
- s = s.translate(str.maketrans('', '', string.punctuation))
+ s = s.translate(str.maketrans('', '', string.punctuation.replace("#", "")))
self.answer_compare = s
@@ -352,6 +352,21 @@ class Exam(ExamBase):
help_text="Exam time limit (in seconds). Default is 2100 secondse (35 minutes)", default=2100
)
+ def get_normal_abnormal_breakdown(self):
+ # Inefficient but more extendible
+ questions = self.exam_questions.all()
+
+ normal = []
+ abnormal = []
+ for q in questions:
+ if q.normal:
+ normal.append(q)
+ else:
+ abnormal.append(q)
+
+ return len(normal)
+
+
def get_exam_json(self):
questions = self.exam_questions.all()
@@ -443,7 +458,7 @@ class CidUserAnswer(models.Model):
self.answer = self.answer.strip()
s = self.answer.lower()
- s = s.translate(str.maketrans('', '', string.punctuation))
+ s = s.translate(str.maketrans('', '', string.punctuation.replace("#", "")))
self.answer_compare = s
diff --git a/rapids/templates/rapids/exam_overview.html b/rapids/templates/rapids/exam_overview.html
index b915f176..f20873b8 100644
--- a/rapids/templates/rapids/exam_overview.html
+++ b/rapids/templates/rapids/exam_overview.html
@@ -6,7 +6,8 @@
Admin Edit
Exam: {{ exam.name }}
- This exam has {{question_number}} questions. Time limit: {{exam.time_limit}} seconds.
+ This exam has {{question_number}} questions. Time limit: {{exam.time_limit}} seconds.
+ Normal {{ exam.get_normal_abnormal_breakdown }}
Exam active:
[When checked the exam will be available to take in the test system]
diff --git a/rapids/views.py b/rapids/views.py
index b0400c81..4f52758e 100755
--- a/rapids/views.py
+++ b/rapids/views.py
@@ -355,6 +355,10 @@ class RapidUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView):
return context
def form_valid(self, form):
+ # save exam orders (there must be a better way to do this)
+ exam_orders = {}
+ for exam in self.object.exams.all():
+ exam_orders[exam] = list(exam.exam_questions.all())
self.object = form.save(commit=False)
self.object.save()
@@ -371,6 +375,14 @@ class RapidUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView):
image_formset.save()
answer_formset.instance = self.object
answer_formset.save()
+
+ # restore exam orders
+ for exam in self.object.exams.all():
+ if exam in exam_orders and self.object in exam_orders[exam]:
+ print(exam_orders[exam])
+ exam.exam_questions.set(exam_orders[exam])
+ exam.save()
+
return response
else:
return super().form_invalid(form)
@@ -529,15 +541,14 @@ def loadJsonAnswer(answer):
posted_answer = answer["ans"]
+ # qidn 1 does not hold answer data (but should always arrive prior to 2)
+ if answer["qidn"] == "1":
+ posted_answer = ""
+
# Normal answers are just posted with the answer "Normal"
normal = False
if posted_answer == "Normal":
normal = True
- posted_answer = ""
- # We can ignore the first ab
- elif answer["qidn"] == "1" and posted_answer == "Abnormal":
- return False
-
if not exiting_answers:
ans = CidUserAnswer(answer=posted_answer, normal=normal, cid=answer["cid"])
@@ -551,8 +562,10 @@ def loadJsonAnswer(answer):
# Update an existing answer
# should never be more than one (famous last words)
ans = exiting_answers[0]
- ans.normal = normal
- ans.answer = posted_answer
+ if answer["qidn"] == "1":
+ ans.normal = normal
+ elif answer["qidn"] == "2":
+ ans.answer = posted_answer
ans.full_clean()
ans.save()
diff --git a/templates/index.html b/templates/index.html
index f9266e0e..87e5eff7 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -6,7 +6,9 @@
Anatomy
Physics
Rapids
+ {% if not request.user.is_authenticated %}
Log in
+ {% endif %}
{% if request.user.is_staff %}
Admin {% endif %}
Reset password