Files

275 lines
8.3 KiB
Python

from django.forms import (
Form,
ModelForm,
ModelMultipleChoiceField,
ModelChoiceField,
ChoiceField,
CharField,
)
from django.forms import inlineformset_factory
from generic.forms import ExamAuthorFormMixin, ExamFormMixin, ExamGroupsFormMixin, ExamMarkerFormMixin
from shorts.models import (
Abnormality,
AnswerMarks,
Examination,
Question,
QuestionFinding,
QuestionImage,
Region,
SampleAnswer,
UserAnswer,
Exam,
)
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.forms.widgets import RadioSelect, TextInput, Textarea
from django.contrib.auth.models import User
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Layout, Div, Field, HTML
from crispy_forms.bootstrap import InlineRadios
from dal import autocomplete
from autocomplete import widgets as htmx_widgets, Autocomplete, AutocompleteWidget, ModelAutocomplete, register as autocomplete_register
from generic.widgets import ExamSearchWidget
class QuestionSampleAnswerForm(ModelForm):
class Meta:
model = Question
fields = []
class MarkQuestionForm(Form):
# correct = forms.CharField(required=False)
# half_correct = forms.CharField(required=False)
# incorrect = forms.CharField(required=False)
marked_answers = CharField(required=False)
#class QuestionAnswerForm(ModelForm):
# class Meta:
# model = Question
# fields = []
class QuestionForm(ModelForm):
# 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
# include <script src="/admin/jsi18n"></script>
# in the template.
css = {
"all": ["css/widgets.css"],
}
# Adding this javascript is crucial
js = ["jsi18n.js", "tesseract.min.js", "js/upload_form_helpers.js"]
def __init__(self, *args, **kwargs):
self.user = kwargs.pop(
"user"
) # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
if kwargs.get("instance"):
# We get the 'initial' keyword argument or initialize it
# as a dict if it didn't exist.
initial = kwargs.setdefault("initial", {})
# The widget for a ModelMultipleChoiceField expects
# 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(QuestionForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'id-anatomy-question-form'
self.helper.form_tag = False
self.helper.layout = Layout(
Div(
HTML("<h4 class='clear-both' id='examination-label'>Examination*</h4>"),
Field('examination', css_class='form-control'),
Field('history', css_class='form-control'),
Field('marking_guidance', css_class='form-control'),
Field('feedback', css_class='form-control'),
Field('open_access', css_class='form-control'),
HTML("<h4 class='clear-both' id='exams-label'>Exams</h4>"),
Field('exams', css_class='form-control'),
))
self.fields["examination"] = ModelMultipleChoiceField(
queryset=Examination.objects.all(),
widget=FilteredSelectMultiple(verbose_name="Examination", is_stacked=False),
)
self.fields["examination"].label = ""
if self.user.groups.filter(name="shorts_checker").exists():
exam_queryset = Exam.objects.all()
else:
exam_queryset = Exam.objects.filter(
author__id=self.user.id
) | Exam.objects.filter(open_access=True)
self.fields["exams"] = ModelMultipleChoiceField(
required=False,
queryset=exam_queryset.distinct(),
widget=ExamSearchWidget(exam_model=Exam),
)
self.fields["exams"].label = ""
self.fields["history"].widget = Textarea(
attrs={"required": "false", "minlength": 2, "maxlength": 500, "rows": 1}
)
def save(self, commit=True):
instance = ModelForm.save(self, False)
instance.save()
old_exams = instance.exams.all()
new_exams = self.cleaned_data["exams"]
for exam in old_exams:
if exam not in new_exams:
exam.exam_questions.remove(instance)
for exam in new_exams:
exam.exam_questions.add(instance)
#exam.save()
# # Prepare a 'save_m2m' method for the form,
# old_save_m2m = self.save_m2m
#
# def save_m2m():
# old_save_m2m()
# # This is where we actually link the pizza with toppings
# instance.exams.clear()
# for exam in self.cleaned_data["exams"]:
# instance.exams.add(exam)
#
# self.save_m2m = save_m2m
#
# # Do we need to save all changes now?
# # if commit:
# instance.save()
self.save_m2m()
return instance
class Meta:
model = Question
# fields = ['due_back']
# fields = '__all__'
fields = [
"examination",
# "site",
"feedback",
"history",
"marking_guidance",
"open_access",
]
# fields = ['question', 'feedback', 'subspecialty', 'references']
ImageFormSet = inlineformset_factory(
Question,
QuestionImage,
fields=["image", "feedback_image", "filename", "description"],
exclude=[],
can_delete=True,
extra=1,
max_num=10,
)
#AnswerFormSet = inlineformset_factory(
# Question,
# SampleAnswer,
# fields=["answer", "status"],
# widgets={
# "answer": Textarea(
# attrs={"required": "false", "minlength": 2, "maxlength": 500, "rows": 3}
# )
# },
# exclude=[],
# can_delete=True,
# extra=0,
# max_num=10,
#)
#
SampleAnswerUpdateFormSet = inlineformset_factory(
Question,
SampleAnswer,
fields=["answer", "score", "proposed"],
widgets={
"answer": Textarea(
attrs={"required": "false", "minlength": 2, "maxlength": 500, "rows": 3}
)
},
exclude=[],
can_delete=True,
extra=0,
max_num=10,
)
# This should be made generic?
class ExamForm(ExamFormMixin, ModelForm):
class Meta(ExamFormMixin.Meta):
model = Exam
class ExamAuthorForm(ExamAuthorFormMixin):
class Meta(ExamAuthorFormMixin.Meta):
model = Exam
class ExamMarkerForm(ExamMarkerFormMixin):
class Meta(ExamMarkerFormMixin.Meta):
model = Exam
class ExamGroupsForm(ExamGroupsFormMixin):
class Meta(ExamGroupsFormMixin.Meta):
model = Exam
class QuestionFindingForm(ModelForm):
class Meta:
model = QuestionFinding
exclude = ["question", "annotation_json", "viewport_json", "current_image_id_index"]
widgets = {
"findings": autocomplete.ModelSelect2Multiple(
url="atlas:finding-autocomplete"
),
"structures": autocomplete.ModelSelect2Multiple(
url="atlas:structure-autocomplete"
),
"conditions": autocomplete.ModelSelect2Multiple(
url="atlas:condition-autocomplete"
),
}
def __init__(self, *args, **kwargs):
if kwargs.get("question_id"):
initial = kwargs.setdefault("initial", {})
initial["question"] = kwargs.pop("question_id")
super(QuestionFindingForm, self).__init__(*args, **kwargs)
ModelForm.__init__(self, *args, **kwargs)
class MarkQuestionSingleForm(ModelForm):
class Meta:
model = UserAnswer
fields = ["score", "candidate_feedback", "marker_feedback"]
widgets = {
"candidate_feedback": Textarea(attrs={"rows": 3}),
"marker_feedback": Textarea(attrs={"rows": 3}),
}
class MarkQuestionDoubleForm(ModelForm):
class Meta:
model = AnswerMarks
fields = ["score", "mark_reason"]