From 8b34b679bacc3b761b859412f092b2e375b03fd3 Mon Sep 17 00:00:00 2001 From: Ross Date: Sun, 27 Mar 2022 10:55:33 +0100 Subject: [PATCH] . --- atlas/forms.py | 656 +++++++++--------- atlas/models.py | 4 + .../templates/atlas/collection_case_view.html | 81 ++- .../atlas/collection_detail_view.html | 6 +- atlas/views.py | 17 +- 5 files changed, 421 insertions(+), 343 deletions(-) diff --git a/atlas/forms.py b/atlas/forms.py index fe594430..0f127ac1 100755 --- a/atlas/forms.py +++ b/atlas/forms.py @@ -1,313 +1,343 @@ -from django.contrib.admin import widgets -from django.forms import ( - Form, - ModelForm, - ModelMultipleChoiceField, - ModelChoiceField, - ChoiceField, - CharField, -) -from django.forms import inlineformset_factory - -from atlas.models import ( - Case, - Differential, - Finding, - Series, - SeriesImage, - SeriesFinding, - Condition, - Structure, -) - -from anatomy.models import Modality - -from generic.models import Examination, Sign - -# from generic.models import Examination, Site, Condition, Sign - -from django.contrib.admin.widgets import FilteredSelectMultiple -from django.forms.widgets import RadioSelect, TextInput, Textarea - -from tinymce.widgets import TinyMCE - -from dal import autocomplete - - -class ConditionForm(ModelForm): - class Meta: - model = Condition - exclude = [] - - widgets = { - "synonym": autocomplete.ModelSelect2Multiple( - url="atlas:condition-autocomplete" - ), - "parent": autocomplete.ModelSelect2Multiple( - url="atlas:condition-autocomplete" - ), - } - - -class FindingForm(ModelForm): - class Meta: - model = Finding - exclude = [] - - widgets = { - "synonym": autocomplete.ModelSelect2Multiple( - url="atlas:finding-autocomplete" - ), - } - - -class StructureForm(ModelForm): - class Meta: - model = Structure - exclude = [] - - widgets = { - "synonym": autocomplete.ModelSelect2Multiple( - url="atlas:structure-autocomplete" - ), - } - - -class SeriesFindingForm(ModelForm): - class Meta: - model = SeriesFinding - exclude = ["series", "annotation_json", "viewport_json"] - - widgets = { - "findings": autocomplete.ModelSelect2Multiple( - url="atlas:finding-autocomplete" - ), - "structures": autocomplete.ModelSelect2Multiple( - url="atlas:structure-autocomplete" - ), - } - - def __init__(self, *args, **kwargs): - if kwargs.get("series_id"): - # 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["series"] = kwargs.pop("series_id") - # elif 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["structures"] = [t.pk for t in kwargs["structures"].case.all()] - # #initial["structures"] = [t.pk for t in kwargs["structures"].case.all()] - - super(SeriesFindingForm, self).__init__(*args, **kwargs) - - ModelForm.__init__(self, *args, **kwargs) - - -class SeriesForm(ModelForm): - class Media: - # Django also includes a few javascript files necessary - # for the operation of this form element. You need to - # include - # in the template. - css = { - "all": ["css/widgets.css"], - } - # Adding this javascript is crucial - js = ["jsi18n.js", "tesseract.min.js"] - - def __init__(self, *args, **kwargs): - 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["case"] = [t.pk for t in kwargs["instance"].case.all()] - - super(SeriesForm, self).__init__(*args, **kwargs) - # self.fields["examination"] = ModelChoiceField( - # queryset=Examination.objects.all(), - # widget=FilteredSelectMultiple(verbose_name="Examination", is_stacked=False), - # ) - - self.fields["modality"] = ModelChoiceField( - required=True, - queryset=Modality.objects.all(), - ) - - ModelForm.__init__(self, *args, **kwargs) - - case_queryset = Case.objects.all() - - self.fields["case"] = ModelMultipleChoiceField( - required=False, - queryset=case_queryset, - widget=FilteredSelectMultiple(verbose_name="Case", is_stacked=False), - ) - - def save(self, commit=True): - # Get the unsaved Long instance - instance = ModelForm.save(self, False) - - # Prepare a 'save_m2m' method for the form, - old_save_m2m = self.save_m2m - - def save_m2m(): - old_save_m2m() - instance.case.clear() - for case in self.cleaned_data["case"]: - # We need the id here - instance.case.add(case.pk) - - 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 = Series - exclude = ["author"] - - widgets = { - "examination": autocomplete.ModelSelect2( - url="generic:examination-autocomplete" - ), - "description": Textarea(attrs={"maxlength": 1000, "rows": 5, "cols": 80}), - } - - -class CaseForm(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 - # in the template. - css = { - "all": ["css/widgets.css"], - } - # Adding this javascript is crucial - js = ["jsi18n.js", "tesseract.min.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(CaseForm, self).__init__(*args, **kwargs) - - class Meta: - model = Case - # fields = ['due_back'] - # fields = '__all__' - fields = [ - # "examination", - # "site", - "title", - "subspecialty", - "description", - "history", - "presentation", - "discussion", - "condition", - "pathological_process", - "report", - "open_access", - "previous_case", - ] - # fields = ['question', 'findings', 'subspecialty', 'references'] - widgets = { - # "normal": RadioSelect( - # choices=[(True, 'Yes'), - # (False, 'No')]) - # "findings": TinyMCE(attrs={"cols": 80, "rows": 20}), - # "mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}), - "description": Textarea(attrs={"cols": 80, "rows": 5}), - "history": Textarea(attrs={"cols": 80, "rows": 5}), - "discussion": Textarea(attrs={"cols": 80, "rows": 5}), - "condition": autocomplete.ModelSelect2Multiple( - url="atlas:condition-autocomplete" - ), - "presentation": autocomplete.ModelSelect2Multiple( - url="atlas:presentation-autocomplete" - ), - } - - def save(self, commit=True): - # Get the unsaved Case instance - instance = ModelForm.save(self, False) - - # Prepare a 'save_m2m' method for the form, - old_save_m2m = self.save_m2m - - def save_m2m(): - old_save_m2m() - # instance.exams.clear() - # for exam in self.cleaned_data["exams"]: - # # We need the id here - # instance.exams.add(exam.pk) - - self.save_m2m = save_m2m - - # Do we need to save all changes now? - # if commit: - instance.save() - self.save_m2m() - - return instance - - -CaseDifferentialFormSet = inlineformset_factory( - Case, - Differential, - exclude=[], - can_delete=True, - extra=1, - max_num=10, - widgets={ - "condition": autocomplete.ModelSelect2(url="atlas:condition-autocomplete"), - "text": Textarea(attrs={"maxlength": 1000, "rows": 3, "cols": 80}), - }, -) - -SeriesFormSet = inlineformset_factory( - Case, - Series.case.through, - exclude=[], - can_delete=True, - extra=0, - max_num=10, - field_classes="testing", -) - - -SeriesImageFormSet = inlineformset_factory( - Series, - SeriesImage, - exclude=[], - can_delete=True, - extra=0, - max_num=2000, - field_classes="testing", -) +from django.contrib.admin import widgets +from django.forms import ( + BaseInlineFormSet, + Form, + ModelForm, + ModelMultipleChoiceField, + ModelChoiceField, + ChoiceField, + CharField, + modelformset_factory, +) +from django.forms import inlineformset_factory + +from atlas.models import ( + Case, + Differential, + Finding, + Series, + SeriesImage, + SeriesFinding, + Condition, + Structure, +) + +from anatomy.models import Modality + +from generic.models import Examination, Sign + +# from generic.models import Examination, Site, Condition, Sign + +from django.contrib.admin.widgets import FilteredSelectMultiple +from django.forms.widgets import RadioSelect, TextInput, Textarea + +from tinymce.widgets import TinyMCE + +from dal import autocomplete + + +class ConditionForm(ModelForm): + class Meta: + model = Condition + exclude = [] + + widgets = { + "synonym": autocomplete.ModelSelect2Multiple( + url="atlas:condition-autocomplete" + ), + "parent": autocomplete.ModelSelect2Multiple( + url="atlas:condition-autocomplete" + ), + } + + +class FindingForm(ModelForm): + class Meta: + model = Finding + exclude = [] + + widgets = { + "synonym": autocomplete.ModelSelect2Multiple( + url="atlas:finding-autocomplete" + ), + } + + +class StructureForm(ModelForm): + class Meta: + model = Structure + exclude = [] + + widgets = { + "synonym": autocomplete.ModelSelect2Multiple( + url="atlas:structure-autocomplete" + ), + } + + +class SeriesFindingForm(ModelForm): + class Meta: + model = SeriesFinding + exclude = ["series", "annotation_json", "viewport_json"] + + widgets = { + "findings": autocomplete.ModelSelect2Multiple( + url="atlas:finding-autocomplete" + ), + "structures": autocomplete.ModelSelect2Multiple( + url="atlas:structure-autocomplete" + ), + } + + def __init__(self, *args, **kwargs): + if kwargs.get("series_id"): + # 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["series"] = kwargs.pop("series_id") + # elif 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["structures"] = [t.pk for t in kwargs["structures"].case.all()] + # #initial["structures"] = [t.pk for t in kwargs["structures"].case.all()] + + super(SeriesFindingForm, self).__init__(*args, **kwargs) + + ModelForm.__init__(self, *args, **kwargs) + + +class SeriesForm(ModelForm): + class Media: + # Django also includes a few javascript files necessary + # for the operation of this form element. You need to + # include + # in the template. + css = { + "all": ["css/widgets.css"], + } + # Adding this javascript is crucial + js = ["jsi18n.js", "tesseract.min.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["case"] = [t.pk for t in kwargs["instance"].case.all()] + + super(SeriesForm, self).__init__(*args, **kwargs) + # self.fields["examination"] = ModelChoiceField( + # queryset=Examination.objects.all(), + # widget=FilteredSelectMultiple(verbose_name="Examination", is_stacked=False), + # ) + + self.fields["modality"] = ModelChoiceField( + required=True, + queryset=Modality.objects.all(), + ) + + ModelForm.__init__(self, *args, **kwargs) + + if self.user.groups.filter(name="atlas_editor").exists(): + case_queryset = Case.objects.all() + else: + case_queryset = Case.objects.filter( + author__id=self.user.id + ) #| Case.objects.filter(open_access=True) + + self.fields["case"] = ModelMultipleChoiceField( + required=False, + queryset=case_queryset, + widget=FilteredSelectMultiple(verbose_name="Case", is_stacked=False), + ) + + def save(self, commit=True): + # Get the unsaved Long instance + instance = ModelForm.save(self, False) + + # Prepare a 'save_m2m' method for the form, + old_save_m2m = self.save_m2m + + def save_m2m(): + old_save_m2m() + instance.case.clear() + for case in self.cleaned_data["case"]: + # We need the id here + instance.case.add(case.pk) + + 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 = Series + exclude = ["author"] + + widgets = { + "examination": autocomplete.ModelSelect2( + url="generic:examination-autocomplete" + ), + "description": Textarea(attrs={"maxlength": 1000, "rows": 5, "cols": 80}), + } + + +class CaseForm(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 + # in the template. + css = { + "all": ["css/widgets.css"], + } + # Adding this javascript is crucial + js = ["jsi18n.js", "tesseract.min.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(CaseForm, self).__init__(*args, **kwargs) + print(1) + + # self.fields["series"].queryset = + + def get_queryset(self, request): + return ( + super() + .get_queryset(request) + .prefetch_related( + "condition", "subspecialty", "pathological_process", "series" + ) + ) + + class Meta: + model = Case + # fields = ['due_back'] + # fields = '__all__' + fields = [ + # "examination", + # "site", + "title", + "subspecialty", + "description", + "history", + "presentation", + "discussion", + "condition", + "pathological_process", + "report", + "open_access", + "previous_case", + ] + # fields = ['question', 'findings', 'subspecialty', 'references'] + widgets = { + # "normal": RadioSelect( + # choices=[(True, 'Yes'), + # (False, 'No')]) + # "findings": TinyMCE(attrs={"cols": 80, "rows": 20}), + # "mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}), + "description": Textarea(attrs={"cols": 80, "rows": 5}), + "history": Textarea(attrs={"cols": 80, "rows": 5}), + "discussion": Textarea(attrs={"cols": 80, "rows": 5}), + "condition": autocomplete.ModelSelect2Multiple( + url="atlas:condition-autocomplete" + ), + "presentation": autocomplete.ModelSelect2Multiple( + url="atlas:presentation-autocomplete" + ), + } + + def save(self, commit=True): + # Get the unsaved Case instance + instance = ModelForm.save(self, False) + + # Prepare a 'save_m2m' method for the form, + old_save_m2m = self.save_m2m + + def save_m2m(): + old_save_m2m() + # instance.exams.clear() + # for exam in self.cleaned_data["exams"]: + # # We need the id here + # instance.exams.add(exam.pk) + + self.save_m2m = save_m2m + + # Do we need to save all changes now? + # if commit: + instance.save() + self.save_m2m() + + return instance + + +CaseDifferentialFormSet = inlineformset_factory( + Case, + Differential, + exclude=[], + can_delete=True, + extra=1, + max_num=10, + widgets={ + "condition": autocomplete.ModelSelect2(url="atlas:condition-autocomplete"), + "text": Textarea(attrs={"maxlength": 1000, "rows": 3, "cols": 80}), + }, +) + +class BaseSeriesFormSet(BaseInlineFormSet): + def __init__(self, *args, **kwargs): + super(BaseSeriesFormSet, self).__init__(*args, **kwargs) + + self.queryset = Series.case.through.objects.filter(series__author__id=99) + + #for form in self.forms: + # form.fields['series'].queryset = series_queryset + +SeriesFormSet = inlineformset_factory( + Case, + Series.case.through, + formset=BaseSeriesFormSet, + exclude=[], + can_delete=True, + extra=1, + max_num=10, +) + + +SeriesImageFormSet = inlineformset_factory( + Series, + SeriesImage, + exclude=[], + can_delete=True, + extra=0, + max_num=2000, +) diff --git a/atlas/models.py b/atlas/models.py index ccd2f292..f4e12a21 100644 --- a/atlas/models.py +++ b/atlas/models.py @@ -400,6 +400,10 @@ class Series(models.Model): ) def __str__(self): + return f"{self.pk}:{self.description}" + + + def get_full_str(self): if self.case: case_id = ", ".format([case.pk for case in self.case.all()]) # case_id = self.case.pk diff --git a/atlas/templates/atlas/collection_case_view.html b/atlas/templates/atlas/collection_case_view.html index b73e872f..f623e033 100644 --- a/atlas/templates/atlas/collection_case_view.html +++ b/atlas/templates/atlas/collection_case_view.html @@ -1,52 +1,81 @@ {% extends 'atlas/base.html' %} {% block content %} -

Case {{case_number|add:1}}

+

Case {{case_number|add:1}} -
- {% for series in series_list %} - - - Series {{ forloop.counter }}: - - {{series.get_block}} - - - - {% endfor %} + {% if collection.show_title %} + : {{case.title}} + {% endif %} + +

+ +{% if collection.show_description and case.description%} +
+ Description: {{case.description}} +
+{% endif %} + +
+ {% for series in series_list %} + + + Series {{ forloop.counter }}: + + {{series.get_block}} + + + + {% endfor %} +
+ +
+
-
-
-
-
+{% if collection.show_discussion and case.discussion%} +
+ + Discussion: + +
+ {{case.discussion}} +
+
+{% endif %}
-{% if previous %} + {% if previous %} Previous -{% endif %} -{% if next %} + {% endif %} + {% if next %} Next -{% endif %} + {% endif %}
-
+
Return to collection {% endblock %} {% block js %} {% endblock js %} \ No newline at end of file diff --git a/atlas/templates/atlas/collection_detail_view.html b/atlas/templates/atlas/collection_detail_view.html index 601fe1aa..0b9f37a9 100644 --- a/atlas/templates/atlas/collection_detail_view.html +++ b/atlas/templates/atlas/collection_detail_view.html @@ -4,7 +4,11 @@

{{collection.name}}
    {% for case in collection.cases.all %} -
  • Case {{forloop.counter}}
  • +
  • Case {{forloop.counter}} + {% if collection.show_title %} + : {{case.title}} + {% endif %} +
  • {% endfor %} diff --git a/atlas/views.py b/atlas/views.py index c163dd18..d4a196e6 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -363,6 +363,11 @@ class SeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView): return initial + def get_form_kwargs(self): + kwargs = super(SeriesCreate, self).get_form_kwargs() + kwargs.update({"user": self.request.user}) + return kwargs + def get_context_data(self, **kwargs): context = super(SeriesCreate, self).get_context_data(**kwargs) @@ -416,6 +421,11 @@ class SeriesUpdate( context["image_formset"] = SeriesImageFormSet(instance=self.object) return context + def get_form_kwargs(self): + kwargs = super(SeriesUpdate, self).get_form_kwargs() + kwargs.update({"user": self.request.user}) + return kwargs + def form_valid(self, form): self.object = form.save(commit=False) @@ -484,7 +494,7 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin): context = super(AtlasCreateBase, self).get_context_data(**kwargs) if self.request.POST: context["series_formset"] = SeriesFormSet( - self.request.POST, self.request.FILES + self.request.POST, self.request.FILES, queryset=Series.objects.filter(author__id=self.request.user.id) ) context["casedifferential_formset"] = CaseDifferentialFormSet( self.request.POST, self.request.FILES @@ -492,6 +502,7 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin): context["series_formset"].full_clean() context["casedifferential_formset"].full_clean() else: + #context["series_formset"] = SeriesFormSet(instance=Case.objects.filter(author__id=self.request.user.id), queryset=Series.objects.filter(author__id=self.request.user.id)) context["series_formset"] = SeriesFormSet() context["casedifferential_formset"] = CaseDifferentialFormSet() return context @@ -558,7 +569,7 @@ class AtlasUpdate( context = super(AtlasUpdate, self).get_context_data(**kwargs) if self.request.POST: context["series_formset"] = SeriesFormSet( - self.request.POST, self.request.FILES, instance=self.object + self.request.POST, self.request.FILES, instance=self.object, queryset=Series.objects.filter(author__id=self.request.user.id) ) context["casedifferential_formset"] = CaseDifferentialFormSet( self.request.POST, self.request.FILES, instance=self.object @@ -566,7 +577,7 @@ class AtlasUpdate( context["series_formset"].full_clean() context["casedifferential_formset"].full_clean() else: - context["series_formset"] = SeriesFormSet(instance=self.object) + context["series_formset"] = SeriesFormSet(instance=self.object, queryset=Series.objects.filter(author__id=self.request.user.id)) context["casedifferential_formset"] = CaseDifferentialFormSet( instance=self.object )