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 %} +
{% csrf_token %} + {{ form | crispy}} + + +
\ 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()