Refactor case collection form to use crispy forms for improved layout and styling

This commit is contained in:
Ross
2025-08-04 13:19:19 +01:00
parent b3304b6113
commit 816b2adde2
2 changed files with 160 additions and 92 deletions
+157 -90
View File
@@ -12,7 +12,7 @@ from django.forms import (
CharField, CharField,
ValidationError, ValidationError,
modelformset_factory, modelformset_factory,
CheckboxSelectMultiple CheckboxSelectMultiple,
) )
from django.forms import inlineformset_factory from django.forms import inlineformset_factory
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
@@ -45,7 +45,7 @@ from atlas.models import (
from anatomy.models import Modality from anatomy.models import Modality
from generic.models import Examination#, Sign from generic.models import Examination # , Sign
# from generic.models import Examination, Site, Condition, Sign # from generic.models import Examination, Site, Condition, Sign
@@ -58,7 +58,13 @@ from tinymce.widgets import TinyMCE
from dal import autocomplete from dal import autocomplete
from autocomplete import widgets as htmx_widgets, Autocomplete, AutocompleteWidget, ModelAutocomplete, register as autocomplete_register from autocomplete import (
widgets as htmx_widgets,
Autocomplete,
AutocompleteWidget,
ModelAutocomplete,
register as autocomplete_register,
)
import logging import logging
@@ -73,28 +79,30 @@ from typing import Any
from helpers.cimar import CimarAPI, NotFoundError from helpers.cimar import CimarAPI, NotFoundError
from rad.settings import CIMAR_USERNAME, CIMAR_PASSWORD from rad.settings import CIMAR_USERNAME, CIMAR_PASSWORD
class ClearableInput(TextInput): class ClearableInput(TextInput):
template_name = "crispy_forms/widgets/clearable_input_single_line.html" template_name = "crispy_forms/widgets/clearable_input_single_line.html"
class ClearableTextarea(Textarea): class ClearableTextarea(Textarea):
template_name = "crispy_forms/widgets/clearable_input.html" template_name = "crispy_forms/widgets/clearable_input.html"
class CaseSelect(Select): class CaseSelect(Select):
template_name = "atlas/case_select_widget.html" template_name = "atlas/case_select_widget.html"
def create_option(self, *args, **kwargs): def create_option(self, *args, **kwargs):
option = super().create_option(*args, **kwargs) option = super().create_option(*args, **kwargs)
return option return option
def get_context(self, name: str, value, attrs) -> dict[str, Any]: def get_context(self, name: str, value, attrs) -> dict[str, Any]:
context = super().get_context(name, value, attrs) context = super().get_context(name, value, attrs)
return context return context
pass pass
class ConditionForm(ModelForm): class ConditionForm(ModelForm):
class Meta: class Meta:
model = Condition model = Condition
@@ -119,26 +127,56 @@ class CaseCollectionForm(ModelForm):
exclude = ["cases", "valid_cid_users", "valid_user_users", "author"] exclude = ["cases", "valid_cid_users", "valid_user_users", "author"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.user = kwargs.pop( self.user = kwargs.pop("user")
"user"
) # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
if kwargs.get("instance"): 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", {}) 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) ModelForm.__init__(self, *args, **kwargs)
super(CaseCollectionForm, self).__init__(*args, **kwargs) super(CaseCollectionForm, self).__init__(*args, **kwargs)
# Identify show_ fields
show_fields = [f for f in self.fields if f.startswith("show_")]
show_pre_fields = [f for f in show_fields if f.endswith("_pre")]
show_post_fields = [f for f in show_fields if f.endswith("_post")]
self.helper = FormHelper()
self.helper.form_id = "id-casecollection-form"
self.helper.form_class = "casecollection-form"
self.helper.form_method = "post"
self.helper.form_action = ""
self.helper.form_tag = True
# Group cid_user_groups and user_user_groups together if they exist in the form
user_fields = []
for f in ["cid_user_groups", "user_user_groups"]:
if f in self.fields:
user_fields.append(f)
other_fields = [f for f in self.fields if f not in show_fields and f not in user_fields]
self.helper.layout = Layout(
Fieldset("Collection Details", *other_fields),
# Add grouped user fields if present
Fieldset("Valid User Groups", *user_fields) if user_fields else None,
Div(
Div(
Fieldset("Show fields (pre-exam)", *show_pre_fields),
css_class="col-md-6",
style="float:left;",
),
Div(
Fieldset("Show fields (post-exam)", *show_post_fields),
css_class="col-md-6",
style="float:left;",
),
css_class="row",
style="display: flex; flex-wrap: wrap;",
),
Submit("submit", "Save Collection", css_class="btn btn-primary"),
)
def save(self, commit=True): def save(self, commit=True):
# Get the unsaved Case instance # Get the unsaved Case instance
instance = ModelForm.save(self, False) instance = ModelForm.save(self, False)
# Do we need to save all changes now? # Do we need to save all changes now?
# if commit: # if commit:
instance.save() instance.save()
@@ -174,7 +212,14 @@ class StructureForm(ModelForm):
class SeriesFindingForm(ModelForm): class SeriesFindingForm(ModelForm):
class Meta: class Meta:
model = SeriesFinding model = SeriesFinding
exclude = ["series", "annotation_json", "viewport_json", "current_image_id_index", "annotation_json_3d", "viewer_state_3d"] exclude = [
"series",
"annotation_json",
"viewport_json",
"current_image_id_index",
"annotation_json_3d",
"viewer_state_3d",
]
widgets = { widgets = {
"findings": autocomplete.ModelSelect2Multiple( "findings": autocomplete.ModelSelect2Multiple(
@@ -186,7 +231,6 @@ class SeriesFindingForm(ModelForm):
"conditions": autocomplete.ModelSelect2Multiple( "conditions": autocomplete.ModelSelect2Multiple(
url="atlas:condition-autocomplete" url="atlas:condition-autocomplete"
), ),
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -297,12 +341,10 @@ class SeriesForm(ModelForm):
"description": Textarea(attrs={"maxlength": 1000, "rows": 5, "cols": 80}), "description": Textarea(attrs={"maxlength": 1000, "rows": 5, "cols": 80}),
} }
# def save(self, commit=True):
#def save(self, commit=True):
# # Get the unsaved Case instance # # Get the unsaved Case instance
# instance = ModelForm.save(self, False) # instance = ModelForm.save(self, False)
# # Prepare a 'save_m2m' method for the form, # # Prepare a 'save_m2m' method for the form,
# old_save_m2m = self.save_m2m # old_save_m2m = self.save_m2m
@@ -320,20 +362,19 @@ class SeriesForm(ModelForm):
# instance.save() # instance.save()
# self.save_m2m() # self.save_m2m()
# return instance # return instance
class CaseForm(ModelForm):
class CaseForm(ModelForm):
class Media: class Media:
# Django also includes a few javascript files necessary # Django also includes a few javascript files necessary
# for the operation of this form element. You need to # for the operation of this form element. You need to
# include <script src="/admin/jsi18n"></script> # include <script src="/admin/jsi18n"></script>
# in the template. # in the template.
#history = forms.CharField( # history = forms.CharField(
# widget=ClearableTextarea(attrs={"maxlength": 1000, "rows": 5, "cols": 80}), # widget=ClearableTextarea(attrs={"maxlength": 1000, "rows": 5, "cols": 80}),
# required=False, # required=False,
#) # )
css = { css = {
"all": ["css/widgets.css"], "all": ["css/widgets.css"],
@@ -348,7 +389,7 @@ class CaseForm(ModelForm):
# This is populated if we create the case from an exam/collection # This is populated if we create the case from an exam/collection
self.collection = None self.collection = None
if kwargs["initial"] is not None and "exams" in kwargs["initial"]: if kwargs["initial"] is not None and "exams" in kwargs["initial"]:
collections = kwargs["initial"].pop("exams") collections = kwargs["initial"].pop("exams")
logging.debug(collections) logging.debug(collections)
@@ -362,20 +403,16 @@ class CaseForm(ModelForm):
# a list of primary key for the selected data. # a list of primary key for the selected data.
# initial["exams"] = [t.pk for t in kwargs["instance"].exams.all()] # initial["exams"] = [t.pk for t in kwargs["instance"].exams.all()]
ModelForm.__init__(self, *args, **kwargs) ModelForm.__init__(self, *args, **kwargs)
super(CaseForm, self).__init__(*args, **kwargs) super(CaseForm, self).__init__(*args, **kwargs)
# self.fields["series"].queryset = # self.fields["series"].queryset =
if self.user.groups.filter(name="atlas_editor").exists(): if self.user.groups.filter(name="atlas_editor").exists():
case_queryset = Case.objects.all().order_by("pk").prefetch_related( case_queryset = Case.objects.all().order_by("pk").prefetch_related()
)
else: else:
case_queryset = get_cases_available_to_user(self.user) case_queryset = get_cases_available_to_user(self.user)
self.fields["previous_case"].queryset=case_queryset self.fields["previous_case"].queryset = case_queryset
self.helper = FormHelper() self.helper = FormHelper()
self.helper.form_id = "id-case-form" self.helper.form_id = "id-case-form"
@@ -401,10 +438,8 @@ class CaseForm(ModelForm):
"diagnostic_certainty", "diagnostic_certainty",
"cimar_uuid", "cimar_uuid",
), ),
) )
def get_queryset(self, request): def get_queryset(self, request):
return ( return (
super() super()
@@ -433,7 +468,7 @@ class CaseForm(ModelForm):
"open_access", "open_access",
"previous_case", "previous_case",
"diagnostic_certainty", "diagnostic_certainty",
"cimar_uuid" "cimar_uuid",
] ]
# fields = ['question', 'findings', 'subspecialty', 'references'] # fields = ['question', 'findings', 'subspecialty', 'references']
widgets = { widgets = {
@@ -457,7 +492,7 @@ class CaseForm(ModelForm):
"pathological_process": CheckboxSelectMultiple(), "pathological_process": CheckboxSelectMultiple(),
"previous_case": CaseSelect(), "previous_case": CaseSelect(),
} }
def clean_cimar_uuid(self): def clean_cimar_uuid(self):
cimar_uuid = self.cleaned_data["cimar_uuid"] cimar_uuid = self.cleaned_data["cimar_uuid"]
if cimar_uuid: if cimar_uuid:
@@ -474,7 +509,6 @@ class CaseForm(ModelForm):
# Get the unsaved Case instance # Get the unsaved Case instance
instance = ModelForm.save(self, False) instance = ModelForm.save(self, False)
# Prepare a 'save_m2m' method for the form, # Prepare a 'save_m2m' method for the form,
old_save_m2m = self.save_m2m old_save_m2m = self.save_m2m
@@ -501,8 +535,10 @@ class CaseForm(ModelForm):
logging.debug(f"{instance=}") logging.debug(f"{instance=}")
# Create through model # Create through model
#cd = CaseDetail(case=instance, collection=exam, sort_order=case_no) # cd = CaseDetail(case=instance, collection=exam, sort_order=case_no)
self.collection.cases.add(instance, through_defaults={"sort_order": case_no}) self.collection.cases.add(
instance, through_defaults={"sort_order": case_no}
)
return instance return instance
@@ -520,6 +556,7 @@ CaseDifferentialFormSet = inlineformset_factory(
}, },
) )
class ResourceForm(ModelForm): class ResourceForm(ModelForm):
class Meta: class Meta:
model = Resource model = Resource
@@ -532,7 +569,6 @@ class ResourceForm(ModelForm):
class CaseResourceForm(ModelForm): class CaseResourceForm(ModelForm):
def __init__(self, *args, user, **kwargs): def __init__(self, *args, user, **kwargs):
super(CaseResourceForm, self).__init__(*args, **kwargs) super(CaseResourceForm, self).__init__(*args, **kwargs)
@@ -550,7 +586,7 @@ class CaseResourceForm(ModelForm):
self.fields["pre_review"] = BooleanField(required=False) self.fields["pre_review"] = BooleanField(required=False)
#class CaseSeriesForm(ModelForm): # class CaseSeriesForm(ModelForm):
# #
# def __init__(self, *args, user, **kwargs): # def __init__(self, *args, user, **kwargs):
# super(CaseSeriesForm, self).__init__(*args, **kwargs) # super(CaseSeriesForm, self).__init__(*args, **kwargs)
@@ -574,7 +610,6 @@ class CaseResourceForm(ModelForm):
# ) # )
class CaseCollectionCaseForm(ModelForm): class CaseCollectionCaseForm(ModelForm):
def __init__(self, *args, user, collection=None, **kwargs): def __init__(self, *args, user, collection=None, **kwargs):
super(CaseCollectionCaseForm, self).__init__(*args, **kwargs) super(CaseCollectionCaseForm, self).__init__(*args, **kwargs)
@@ -588,7 +623,7 @@ class CaseCollectionCaseForm(ModelForm):
) )
#SeriesFormSet = inlineformset_factory( # SeriesFormSet = inlineformset_factory(
# Case, # Case,
# Series.case.through, # Series.case.through,
# form=CaseSeriesForm, # form=CaseSeriesForm,
@@ -596,7 +631,7 @@ class CaseCollectionCaseForm(ModelForm):
# can_delete=True, # can_delete=True,
# extra=0, # extra=0,
# max_num=10, # max_num=10,
#) # )
CaseCollectionCaseFormSet = inlineformset_factory( CaseCollectionCaseFormSet = inlineformset_factory(
CaseCollection, CaseCollection,
@@ -621,7 +656,13 @@ CaseResourceFormSet = inlineformset_factory(
SeriesImageFormSet = inlineformset_factory( SeriesImageFormSet = inlineformset_factory(
Series, Series,
SeriesImage, SeriesImage,
exclude=["dicom_tags_ohif", "replaced", "image_md5_hash", "image_blake3_hash", "is_dicom"], exclude=[
"dicom_tags_ohif",
"replaced",
"image_md5_hash",
"image_blake3_hash",
"is_dicom",
],
can_delete=True, can_delete=True,
extra=0, extra=0,
max_num=2000, max_num=2000,
@@ -630,19 +671,23 @@ SeriesImageFormSet = inlineformset_factory(
class JsonAnswerForm(Form): class JsonAnswerForm(Form):
json_answer = JSONSchemaField( json_answer = JSONSchemaField(
schema = {}, schema={},
#options = 'schema/options.json' # options = 'schema/options.json'
options = 'schema/options.json' options="schema/options.json",
) )
class Meta: class Meta:
fields = ["json_answer"] fields = ["json_answer"]
def __init__(self, *args, question_schema=None, **kwargs): def __init__(self, *args, question_schema=None, **kwargs):
super(JsonAnswerForm, self).__init__(*args, **kwargs) super(JsonAnswerForm, self).__init__(*args, **kwargs)
if question_schema is not None: if question_schema is not None:
self.fields["json_answer"] = JSONSchemaField(schema=question_schema, options='schema/options.json') self.fields["json_answer"] = JSONSchemaField(
schema=question_schema, options="schema/options.json"
)
self.fields["json_answer"].label = False self.fields["json_answer"].label = False
class BaseReportAnswerForm(ModelForm): class BaseReportAnswerForm(ModelForm):
class Meta: class Meta:
fields = ["answer"] fields = ["answer"]
@@ -653,22 +698,23 @@ class BaseReportAnswerForm(ModelForm):
# (False, 'No')]) # (False, 'No')])
# "findings": TinyMCE(attrs={"cols": 80, "rows": 20}), # "findings": TinyMCE(attrs={"cols": 80, "rows": 20}),
# "mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}), # "mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}),
"answer": Textarea(attrs={"cols": 100, "rows": 5, "placeholder":"Report text"}), "answer": Textarea(
attrs={"cols": 100, "rows": 5, "placeholder": "Report text"}
),
} }
# help_texts = { # help_texts = {
# "answer": "Write your answer in here." # "answer": "Write your answer in here."
# } # }
def __init__(self, *args, case_detail, **kwargs): def __init__(self, *args, case_detail, **kwargs):
super(BaseReportAnswerForm, self).__init__(*args, **kwargs) super(BaseReportAnswerForm, self).__init__(*args, **kwargs)
self.fields["answer"].required = False self.fields["answer"].required = False
class BaseQuestionAnswerForm(ModelForm): class BaseQuestionAnswerForm(ModelForm):
json_answer = JSONSchemaField( json_answer = JSONSchemaField(schema={}, options="schema/options.json")
schema = {},
options = 'schema/options.json'
)
class Meta: class Meta:
fields = ["json_answer"] fields = ["json_answer"]
labels = {"json_answer": ""} labels = {"json_answer": ""}
@@ -677,11 +723,13 @@ class BaseQuestionAnswerForm(ModelForm):
# "answer": "Write your answer in here." # "answer": "Write your answer in here."
# } # }
def __init__(self, *args, case_detail, **kwargs): def __init__(self, *args, case_detail, **kwargs):
super(BaseQuestionAnswerForm, self).__init__(*args, **kwargs) super(BaseQuestionAnswerForm, self).__init__(*args, **kwargs)
#self.fields["json_answer"].schema = case_detail.question_schema # self.fields["json_answer"].schema = case_detail.question_schema
if case_detail.question_schema is not None: if case_detail.question_schema is not None:
self.fields["json_answer"] = JSONSchemaField(schema=case_detail.question_schema, options="schema/options.json") self.fields["json_answer"] = JSONSchemaField(
schema=case_detail.question_schema, options="schema/options.json"
)
self.fields["json_answer"].label = "" self.fields["json_answer"].label = ""
@@ -689,18 +737,22 @@ class CidReportAnswerForm(BaseReportAnswerForm):
class Meta(BaseReportAnswerForm.Meta): class Meta(BaseReportAnswerForm.Meta):
model = CidReportAnswer model = CidReportAnswer
class UserReportAnswerForm(BaseReportAnswerForm): class UserReportAnswerForm(BaseReportAnswerForm):
class Meta(BaseReportAnswerForm.Meta): class Meta(BaseReportAnswerForm.Meta):
model = UserReportAnswer model = UserReportAnswer
class CidQuestionAnswerForm(BaseQuestionAnswerForm): class CidQuestionAnswerForm(BaseQuestionAnswerForm):
class Meta(BaseQuestionAnswerForm.Meta): class Meta(BaseQuestionAnswerForm.Meta):
model = CidReportAnswer model = CidReportAnswer
class UserQuestionAnswerForm(BaseQuestionAnswerForm): class UserQuestionAnswerForm(BaseQuestionAnswerForm):
class Meta(BaseQuestionAnswerForm.Meta): class Meta(BaseQuestionAnswerForm.Meta):
model = UserReportAnswer model = UserReportAnswer
class CidReportAnswerMarkForm(ModelForm): class CidReportAnswerMarkForm(ModelForm):
class Meta: class Meta:
model = CidReportAnswer model = CidReportAnswer
@@ -720,7 +772,7 @@ class CidReportAnswerMarkForm(ModelForm):
self.fields["score"].required = False self.fields["score"].required = False
#class AddCollectionToCaseForm(Form): # class AddCollectionToCaseForm(Form):
# #
# def __init__(self, *args, user, **kwargs): # def __init__(self, *args, user, **kwargs):
# super(AddCollectionToCaseForm, self).__init__(*args, **kwargs) # super(AddCollectionToCaseForm, self).__init__(*args, **kwargs)
@@ -729,7 +781,7 @@ class CidReportAnswerMarkForm(ModelForm):
# queryset = CaseCollection.objects.filter(author__id=user.id) # queryset = CaseCollection.objects.filter(author__id=user.id)
# else: # else:
# queryset = CaseCollection.objects.all() # queryset = CaseCollection.objects.all()
# #
# self.valid_collections = queryset # self.valid_collections = queryset
# self.case = get_object_or_404(Case, pk=pk) # self.case = get_object_or_404(Case, pk=pk)
# #
@@ -761,8 +813,8 @@ class CidReportAnswerMarkForm(ModelForm):
# #
# return collection_set # return collection_set
class AddCollectionToCaseForm(Form):
class AddCollectionToCaseForm(Form):
def __init__(self, *args, user, **kwargs): def __init__(self, *args, user, **kwargs):
super(AddCollectionToCaseForm, self).__init__(*args, **kwargs) super(AddCollectionToCaseForm, self).__init__(*args, **kwargs)
@@ -770,7 +822,7 @@ class AddCollectionToCaseForm(Form):
queryset = CaseCollection.objects.filter(author__id=user.id) queryset = CaseCollection.objects.filter(author__id=user.id)
else: else:
queryset = CaseCollection.objects.all() queryset = CaseCollection.objects.all()
self.valid_collections = queryset self.valid_collections = queryset
self.fields["casecollection"] = ModelMultipleChoiceField( self.fields["casecollection"] = ModelMultipleChoiceField(
@@ -783,7 +835,7 @@ class AddCollectionToCaseForm(Form):
instance = super(AddCollectionToCaseForm, self).save(*args, **kwargs) instance = super(AddCollectionToCaseForm, self).save(*args, **kwargs)
# Here we save the modified project selection back into the database # Here we save the modified project selection back into the database
instance.casecollection_set.set(self.cleaned_data['casecollection']) instance.casecollection_set.set(self.cleaned_data["casecollection"])
return instance return instance
@@ -798,7 +850,6 @@ class AddCollectionToCaseForm(Form):
class SelfReviewForm(ModelForm): class SelfReviewForm(ModelForm):
class Meta: class Meta:
model = SelfReview model = SelfReview
fields = ["user_exam", "case", "comments", "findings", "interpretation"] fields = ["user_exam", "case", "comments", "findings", "interpretation"]
@@ -813,16 +864,16 @@ class SelfReviewForm(ModelForm):
ModelForm.__init__(self, *args, **kwargs) ModelForm.__init__(self, *args, **kwargs)
super(SelfReviewForm, self).__init__(*args, **kwargs) super(SelfReviewForm, self).__init__(*args, **kwargs)
class UncategorisedDicomForm(ModelForm): class UncategorisedDicomForm(ModelForm):
class Meta: class Meta:
model = UncategorisedDicom model = UncategorisedDicom
fields = ["image"]#, "user"] fields = ["image"] # , "user"]
#UncategorisedDicomFormset = formset_factory(UncategorisedDicomForm) # UncategorisedDicomFormset = formset_factory(UncategorisedDicomForm)
#class ConditionAutocompleteFormModel(forms.ModelForm): # class ConditionAutocompleteFormModel(forms.ModelForm):
# class Meta: # class Meta:
# model = Condition # model = Condition
# fields = ["name"] # fields = ["name"]
@@ -833,49 +884,56 @@ class UncategorisedDicomForm(ModelForm):
# ) # )
# } # }
class ConditionAutocomplete(ModelAutocomplete): class ConditionAutocomplete(ModelAutocomplete):
model = Condition model = Condition
search_attrs = ["name"] search_attrs = ["name"]
class ConditionAutocompleteForm(Form):
condition = ModelChoiceField(queryset=Condition.objects.all(), widget=AutocompleteWidget(
ac_class=ConditionAutocomplete#, options=dict(model=Condition)
)) class ConditionAutocompleteForm(Form):
condition = ModelChoiceField(
queryset=Condition.objects.all(),
widget=AutocompleteWidget(
ac_class=ConditionAutocomplete # , options=dict(model=Condition)
),
)
autocomplete_register(ConditionAutocomplete) autocomplete_register(ConditionAutocomplete)
class CaseCollectionAuthorForm(ExamAuthorFormMixin): class CaseCollectionAuthorForm(ExamAuthorFormMixin):
class Meta(ExamAuthorFormMixin.Meta): class Meta(ExamAuthorFormMixin.Meta):
model = CaseCollection model = CaseCollection
class CaseAuthorForm(ExamAuthorFormMixin): class CaseAuthorForm(ExamAuthorFormMixin):
class Meta(ExamAuthorFormMixin.Meta): class Meta(ExamAuthorFormMixin.Meta):
model = Case model = Case
class SeriesAuthorForm(ExamAuthorFormMixin): class SeriesAuthorForm(ExamAuthorFormMixin):
class Meta(ExamAuthorFormMixin.Meta): class Meta(ExamAuthorFormMixin.Meta):
model = Series model = Series
class ExamGroupsForm(ExamGroupsFormMixin): class ExamGroupsForm(ExamGroupsFormMixin):
class Meta(ExamGroupsFormMixin.Meta): class Meta(ExamGroupsFormMixin.Meta):
model = CaseCollection model = CaseCollection
class AnswerJSONForm(Form):
json = JSONSchemaField( class AnswerJSONForm(Form):
schema = 'schema/schema.json', json = JSONSchemaField(schema="schema/schema.json", options="schema/options.json")
options = 'schema/options.json'
)
class SvelteJSONEditorWidgetOverride(SvelteJSONEditorWidget): class SvelteJSONEditorWidgetOverride(SvelteJSONEditorWidget):
template_name = "atlas/svelte_jsoneditor_widget_override.html" template_name = "atlas/svelte_jsoneditor_widget_override.html"
class CaseDetailForm(ModelForm):
class CaseDetailForm(ModelForm):
class Meta: class Meta:
model = CaseDetail model = CaseDetail
fields = ["question_schema", "question_answers"]#, "user"] fields = ["question_schema", "question_answers"] # , "user"]
widgets = { widgets = {
"question_schema": SvelteJSONEditorWidgetOverride(), "question_schema": SvelteJSONEditorWidgetOverride(),
@@ -892,20 +950,19 @@ class QuestionSchemaForm(ModelForm):
"schema": SvelteJSONEditorWidgetOverride(), "schema": SvelteJSONEditorWidgetOverride(),
} }
#class ModelPriorCaseForm(ModelForm):
# class ModelPriorCaseForm(ModelForm):
# class Meta: # class Meta:
# model = CasePrior # model = CasePrior
# fields = ["case_detail", "prior_case", "relation_text", "prior_visibility"] # fields = ["case_detail", "prior_case", "relation_text", "prior_visibility"]
class PriorCaseForm(Form):
class PriorCaseForm(Form):
relation = CharField(max_length=255, required=True) relation = CharField(max_length=255, required=True)
prior_visibility = CharField(max_length=2, required=True) prior_visibility = CharField(max_length=2, required=True)
# def __init__(self, *args, **kwargs):
#def __init__(self, *args, **kwargs):
# self.case_detail = kwargs.pop( # self.case_detail = kwargs.pop(
# "case_detail" # "case_detail"
# ) # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole # ) # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
@@ -922,6 +979,7 @@ class PriorCaseForm(Form):
# # widget=Select(verbose_name="Series", is_stacked=False), # # widget=Select(verbose_name="Series", is_stacked=False),
# ) # )
class CaseSeriesForm(forms.ModelForm): class CaseSeriesForm(forms.ModelForm):
def __init__(self, *args, queryset, user=None, is_atlas_editor=False, **kwargs): def __init__(self, *args, queryset, user=None, is_atlas_editor=False, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@@ -931,6 +989,7 @@ class CaseSeriesForm(forms.ModelForm):
model = SeriesDetail # through model for Case.series model = SeriesDetail # through model for Case.series
fields = ["series", "sort_order", "feedback"] fields = ["series", "sort_order", "feedback"]
class CaseUpdateSeriesForm(forms.ModelForm): class CaseUpdateSeriesForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user") self.user = kwargs.pop("user")
@@ -942,10 +1001,12 @@ class CaseUpdateSeriesForm(forms.ModelForm):
self.helper.form_action = "submit" self.helper.form_action = "submit"
self.helper.form_tag = False self.helper.form_tag = False
self.helper.layout = Layout() self.helper.layout = Layout()
class Meta: class Meta:
model = Case model = Case
fields = [] # No fields, just for compatibility with UpdateView fields = [] # No fields, just for compatibility with UpdateView
class BaseSeriesFormSet(BaseInlineFormSet): class BaseSeriesFormSet(BaseInlineFormSet):
def __init__(self, *args, queryset=None, **kwargs): def __init__(self, *args, queryset=None, **kwargs):
self.series_queryset = queryset self.series_queryset = queryset
@@ -953,7 +1014,7 @@ class BaseSeriesFormSet(BaseInlineFormSet):
def get_form_kwargs(self, index): def get_form_kwargs(self, index):
kwargs = super().get_form_kwargs(index) kwargs = super().get_form_kwargs(index)
kwargs['queryset'] = self.series_queryset kwargs["queryset"] = self.series_queryset
return kwargs return kwargs
@@ -966,6 +1027,7 @@ SeriesFormSet = inlineformset_factory(
can_delete=True, can_delete=True,
) )
class CaseDisplaySetForm(forms.ModelForm): class CaseDisplaySetForm(forms.ModelForm):
class Meta: class Meta:
model = CaseDisplaySet model = CaseDisplaySet
@@ -977,8 +1039,12 @@ class CaseDisplaySetForm(forms.ModelForm):
"conditions", "conditions",
] ]
widgets = { widgets = {
"name": forms.TextInput(attrs={"class": "form-control", "placeholder": "Display Set Name"}), "name": forms.TextInput(
"description": forms.Textarea(attrs={"class": "form-control", "rows": 3, "placeholder": "Description"}), attrs={"class": "form-control", "placeholder": "Display Set Name"}
),
"description": forms.Textarea(
attrs={"class": "form-control", "rows": 3, "placeholder": "Description"}
),
"findings": autocomplete.ModelSelect2Multiple( "findings": autocomplete.ModelSelect2Multiple(
url="atlas:finding-autocomplete" url="atlas:finding-autocomplete"
), ),
@@ -1007,6 +1073,7 @@ class CaseCollectionUpdateCaseForm(forms.ModelForm):
self.helper.form_action = "submit" self.helper.form_action = "submit"
self.helper.form_tag = False self.helper.form_tag = False
self.helper.layout = Layout() self.helper.layout = Layout()
class Meta: class Meta:
model = CaseCollection model = CaseCollection
fields = [] # No fields, just for compatibility with UpdateView fields = [] # No fields, just for compatibility with UpdateView
@@ -1,5 +1,6 @@
{% extends "atlas/exams.html" %} {% extends "atlas/exams.html" %}
<!-- {% load static from static %} --> <!-- {% load static from static %} -->
{% load crispy_forms_tags %}
{% block css %} {% block css %}
{% endblock %} {% endblock %}
@@ -36,7 +37,7 @@
<form class="highlight" action="" method="post" enctype="multipart/form-data" id="atlas-form"> <form class="highlight" action="" method="post" enctype="multipart/form-data" id="atlas-form">
{% csrf_token %} {% csrf_token %}
{{ form }} {% crispy form form.helper %}
{% comment %} <h3>Cases:</h3> {% comment %} <h3>Cases:</h3>
Add cases here. These can only be added once created (they can also be added to cases on creation). Click and drag to change order. Add cases here. These can only be added once created (they can also be added to cases on creation). Click and drag to change order.
<input type="button" value="Add More Cases" id="add_more_case"> <input type="button" value="Add More Cases" id="add_more_case">
@@ -60,7 +61,7 @@
{{ case_formset.empty_form }} {{ case_formset.empty_form }}
</li> </li>
</div> {% endcomment %} </div> {% endcomment %}
<input type="submit" class="submit-button" value="Submit" name="submit"> {% comment %} <input type="submit" class="submit-button" value="Submit" name="submit"> {% endcomment %}
</form> </form>
<script> <script>
$(document).ready(() => { $(document).ready(() => {