diff --git a/anatomy/forms.py b/anatomy/forms.py
index e08f3e2b..7b4151ee 100644
--- a/anatomy/forms.py
+++ b/anatomy/forms.py
@@ -252,4 +252,9 @@ class ExamMarkerForm(ExamMarkerFormMixin):
class ExamGroupsForm(ExamGroupsFormMixin):
class Meta(ExamGroupsFormMixin.Meta):
- model = Exam
\ No newline at end of file
+ model = Exam
+
+class SuggestIncorrectAnswerForm(ModelForm):
+ class Meta:
+ model = AnatomyQuestion
+ fields = ["answer_suggest_incorrect"]
\ No newline at end of file
diff --git a/anatomy/models.py b/anatomy/models.py
index 0512444c..101598e2 100644
--- a/anatomy/models.py
+++ b/anatomy/models.py
@@ -340,6 +340,9 @@ class Answer(models.Model):
def get_answer_url_safe(self):
return urllib.parse.quote(self.answer_compare)
+ def get_constituent_words(self):
+ return self.answer_compare.split()
+
# def get_compare_string(self):
# s = self.answer.lower().strip()
# s = s.translate(str.maketrans('', '', string.punctuation))
diff --git a/anatomy/templates/anatomy/mark.html b/anatomy/templates/anatomy/mark.html
index 4b7a52e0..7884d2fb 100644
--- a/anatomy/templates/anatomy/mark.html
+++ b/anatomy/templates/anatomy/mark.html
@@ -15,7 +15,28 @@
{% if question.answer_help %}
Marking help:
+
{{question.answer_help|safe}}
+
+
+
+ Suggest incorrect answers:
+
+ {% for word in words_suggest_incorrect %}
+ {{word}}(+),
+ {% endfor %}
+
+
+ {% include "anatomy/question_detail.html#suggest-incorrect-form" %}
+
{% endif %}
diff --git a/anatomy/templates/anatomy/question_detail.html b/anatomy/templates/anatomy/question_detail.html
index fe47d248..42f55b53 100644
--- a/anatomy/templates/anatomy/question_detail.html
+++ b/anatomy/templates/anatomy/question_detail.html
@@ -1,5 +1,5 @@
{% extends 'anatomy/base.html' %}
-
+{% load partials %}
{% block content %}
{% load static %}
{% include 'anatomy/question_link_header.html' %}
@@ -58,7 +58,14 @@
Answer help: {{ question.answer_help|safe }}
- Answer suggest incorrect: {{ question.answer_suggest_incorrect }}
+ {% partialdef suggest-incorrect-form inline %}
+
+ Answer suggest incorrect: {{ question.answer_suggest_incorrect }}
+
+
+ {% endpartialdef %}
Description: {{ question.description }}
diff --git a/anatomy/templates/anatomy/suggest_incorrect.html b/anatomy/templates/anatomy/suggest_incorrect.html
new file mode 100644
index 00000000..31256261
--- /dev/null
+++ b/anatomy/templates/anatomy/suggest_incorrect.html
@@ -0,0 +1,8 @@
+{% load crispy_forms_tags %}
+
\ No newline at end of file
diff --git a/anatomy/urls.py b/anatomy/urls.py
index a38048b8..5871d41a 100644
--- a/anatomy/urls.py
+++ b/anatomy/urls.py
@@ -33,6 +33,12 @@ urlpatterns = [
views.question_save_annotation,
name="question_save_annotation",
),
+ path(
+ "question//suggest_incorrect_answers",
+ views.question_suggest_incorrect_answers,
+ name="question_suggest_incorrect_answers",
+ ),
+
path("question//answer/", views.answer_question, name="answer_question"),
path(
"question//clone", views.QuestionClone.as_view(), name="question_clone"
diff --git a/anatomy/views.py b/anatomy/views.py
index b2736733..8522a412 100644
--- a/anatomy/views.py
+++ b/anatomy/views.py
@@ -44,6 +44,7 @@ from .forms import (
MarkAnatomyQuestionForm,
AnatomyQuestionForm,
ExamForm,
+ SuggestIncorrectAnswerForm,
)
from .models import (
AnatomyQuestion,
@@ -345,6 +346,10 @@ def mark(request, exam_pk, sk, unmarked_exam_answers_only=True, review=False):
incorrect_answers = question.answers.filter(status=Answer.MarkOptions.INCORRECT)
answer_suggest_incorrect: list = []
+
+ words_present: set = set()
+ words_present_in_correct: set = set()
+
if review:
for ans in unmarked_user_answers:
# duplicated from user answer model....
@@ -367,6 +372,22 @@ def mark(request, exam_pk, sk, unmarked_exam_answers_only=True, review=False):
answer_suggest_incorrect.append(ans)
break
+ for ans in correct_answers:
+ answer_words = set(ans.get_constituent_words())
+ words_present.update(answer_words)
+ words_present_in_correct.update(answer_words)
+
+ for ans in half_mark_answers:
+ answer_words = set(ans.get_constituent_words())
+ words_present.update(answer_words)
+ words_present_in_correct.update(answer_words)
+
+ for ans in incorrect_answers:
+ answer_words = set(ans.get_constituent_words())
+ words_present.update(answer_words)
+
+ words_suggest_incorrect = words_present - words_present_in_correct - set(question.answer_suggest_incorrect)
+
return render(
request,
"anatomy/mark.html",
@@ -385,6 +406,7 @@ def mark(request, exam_pk, sk, unmarked_exam_answers_only=True, review=False):
"incorrect_answers": incorrect_answers,
"unmarked_exam_answers_only": unmarked_exam_answers_only,
"answer_suggest_incorrect": answer_suggest_incorrect,
+ "words_suggest_incorrect": words_suggest_incorrect,
},
)
@@ -748,6 +770,25 @@ class AnatomyQuestionView(LoginRequiredMixin, SingleTableMixin, FilterView):
# return qs
+@user_is_author_or_anatomy_checker
+def question_suggest_incorrect_answers(request, pk):
+ question = get_object_or_404(AnatomyQuestion, pk=pk)
+ if request.method == "POST":
+ form = SuggestIncorrectAnswerForm(request.POST, instance=question)
+
+ if form.is_valid():
+ obj = form.save()
+ obj.save()
+
+ return render(request, "anatomy/question_detail.html#suggest-incorrect-form", {"question": question})
+
+ return HttpResponse("Invalid")
+ else:
+ form = SuggestIncorrectAnswerForm(instance=question)
+
+ return render(request, "anatomy/suggest_incorrect.html", {"form": form, "question": question})
+
+ return HttpResponse("Error", status=400)
@user_is_author_or_anatomy_checker
def question_save_annotation(request, pk):
diff --git a/atlas/models.py b/atlas/models.py
index 090c1115..c95ca0e9 100644
--- a/atlas/models.py
+++ b/atlas/models.py
@@ -568,24 +568,6 @@ class SeriesImage(SeriesImageBase):
help_text="Reference to the object that has replaced this one.",
)
- def get_file_size(self):
- try:
- return self.image.size
-
- # We catch this for when the image does not exist
- except FileNotFoundError:
- return 0
-
- def get_dicom_data(self):
- try:
- with pydicom.dcmread(self.image) as d:
- return d
- except InvalidDicomError:
- return {}
-
- def get_series(self):
- return self.series
-
# def get_image_dicom_json(self, image_index):
# try:
# with pydicom.dcmread(self.image) as ds:
diff --git a/generic/models.py b/generic/models.py
index 729a6444..4275b514 100644
--- a/generic/models.py
+++ b/generic/models.py
@@ -37,6 +37,7 @@ from easy_thumbnails.exceptions import InvalidImageFormatError
import pydicom
+import pydicom.errors
import dicognito.anonymizer
from django.contrib.auth.models import User
from django.forms.models import model_to_dict
@@ -240,6 +241,24 @@ class SeriesImageBase(models.Model):
ordering = ["position"]
abstract = True
+ def get_file_size(self):
+ try:
+ return self.image.size
+
+ # We catch this for when the image does not exist
+ except FileNotFoundError:
+ return 0
+
+ def get_dicom_data(self):
+ try:
+ with pydicom.dcmread(self.image) as d:
+ return d
+ except pydicom.errors.InvalidDicomError:
+ return {}
+
+ def get_series(self):
+ return self.series
+
def get_dicom_json(self):
try:
json = pydicom.read_file(self.image).to_json()
diff --git a/generic/views.py b/generic/views.py
index 6a7b496a..7dfec8fe 100644
--- a/generic/views.py
+++ b/generic/views.py
@@ -1525,6 +1525,7 @@ class ExamViews(View, LoginRequiredMixin):
# #queryset=self.Answer.objects.filter(),
# ),
)
+ .order_by("examquestiondetail__sort_order")
)
else:
questions = exam.get_questions()