This commit is contained in:
Ross
2022-03-27 10:55:33 +01:00
parent 6500428cd9
commit 8b34b679ba
5 changed files with 421 additions and 343 deletions
+343 -313
View File
@@ -1,313 +1,343 @@
from django.contrib.admin import widgets from django.contrib.admin import widgets
from django.forms import ( from django.forms import (
Form, BaseInlineFormSet,
ModelForm, Form,
ModelMultipleChoiceField, ModelForm,
ModelChoiceField, ModelMultipleChoiceField,
ChoiceField, ModelChoiceField,
CharField, ChoiceField,
) CharField,
from django.forms import inlineformset_factory modelformset_factory,
)
from atlas.models import ( from django.forms import inlineformset_factory
Case,
Differential, from atlas.models import (
Finding, Case,
Series, Differential,
SeriesImage, Finding,
SeriesFinding, Series,
Condition, SeriesImage,
Structure, SeriesFinding,
) Condition,
Structure,
from anatomy.models import Modality )
from generic.models import Examination, Sign from anatomy.models import Modality
# from generic.models import Examination, Site, Condition, Sign from generic.models import Examination, Sign
from django.contrib.admin.widgets import FilteredSelectMultiple # from generic.models import Examination, Site, Condition, Sign
from django.forms.widgets import RadioSelect, TextInput, Textarea
from django.contrib.admin.widgets import FilteredSelectMultiple
from tinymce.widgets import TinyMCE from django.forms.widgets import RadioSelect, TextInput, Textarea
from dal import autocomplete from tinymce.widgets import TinyMCE
from dal import autocomplete
class ConditionForm(ModelForm):
class Meta:
model = Condition class ConditionForm(ModelForm):
exclude = [] class Meta:
model = Condition
widgets = { exclude = []
"synonym": autocomplete.ModelSelect2Multiple(
url="atlas:condition-autocomplete" widgets = {
), "synonym": autocomplete.ModelSelect2Multiple(
"parent": autocomplete.ModelSelect2Multiple( url="atlas:condition-autocomplete"
url="atlas:condition-autocomplete" ),
), "parent": autocomplete.ModelSelect2Multiple(
} url="atlas:condition-autocomplete"
),
}
class FindingForm(ModelForm):
class Meta:
model = Finding class FindingForm(ModelForm):
exclude = [] class Meta:
model = Finding
widgets = { exclude = []
"synonym": autocomplete.ModelSelect2Multiple(
url="atlas:finding-autocomplete" widgets = {
), "synonym": autocomplete.ModelSelect2Multiple(
} url="atlas:finding-autocomplete"
),
}
class StructureForm(ModelForm):
class Meta:
model = Structure class StructureForm(ModelForm):
exclude = [] class Meta:
model = Structure
widgets = { exclude = []
"synonym": autocomplete.ModelSelect2Multiple(
url="atlas:structure-autocomplete" widgets = {
), "synonym": autocomplete.ModelSelect2Multiple(
} url="atlas:structure-autocomplete"
),
}
class SeriesFindingForm(ModelForm):
class Meta:
model = SeriesFinding class SeriesFindingForm(ModelForm):
exclude = ["series", "annotation_json", "viewport_json"] class Meta:
model = SeriesFinding
widgets = { exclude = ["series", "annotation_json", "viewport_json"]
"findings": autocomplete.ModelSelect2Multiple(
url="atlas:finding-autocomplete" widgets = {
), "findings": autocomplete.ModelSelect2Multiple(
"structures": autocomplete.ModelSelect2Multiple( url="atlas:finding-autocomplete"
url="atlas:structure-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 def __init__(self, *args, **kwargs):
# as a dict if it didn't exist. if kwargs.get("series_id"):
initial = kwargs.setdefault("initial", {}) # We get the 'initial' keyword argument or initialize it
# The widget for a ModelMultipleChoiceField expects # as a dict if it didn't exist.
# a list of primary key for the selected data. initial = kwargs.setdefault("initial", {})
initial["series"] = kwargs.pop("series_id") # The widget for a ModelMultipleChoiceField expects
# elif kwargs.get("instance"): # a list of primary key for the selected data.
# # We get the 'initial' keyword argument or initialize it initial["series"] = kwargs.pop("series_id")
# # as a dict if it didn't exist. # elif kwargs.get("instance"):
# initial = kwargs.setdefault("initial", {}) # # We get the 'initial' keyword argument or initialize it
# # The widget for a ModelMultipleChoiceField expects # # as a dict if it didn't exist.
# # a list of primary key for the selected data. # initial = kwargs.setdefault("initial", {})
# #initial["structures"] = [t.pk for t in kwargs["structures"].case.all()] # # The widget for a ModelMultipleChoiceField expects
# #initial["structures"] = [t.pk for t in kwargs["structures"].case.all()] # # a list of primary key for the selected data.
# #initial["structures"] = [t.pk for t in kwargs["structures"].case.all()]
super(SeriesFindingForm, self).__init__(*args, **kwargs) # #initial["structures"] = [t.pk for t in kwargs["structures"].case.all()]
ModelForm.__init__(self, *args, **kwargs) super(SeriesFindingForm, self).__init__(*args, **kwargs)
ModelForm.__init__(self, *args, **kwargs)
class SeriesForm(ModelForm):
class Media:
# Django also includes a few javascript files necessary class SeriesForm(ModelForm):
# for the operation of this form element. You need to class Media:
# include <script src="/admin/jsi18n"></script> # Django also includes a few javascript files necessary
# in the template. # for the operation of this form element. You need to
css = { # include <script src="/admin/jsi18n"></script>
"all": ["css/widgets.css"], # in the template.
} css = {
# Adding this javascript is crucial "all": ["css/widgets.css"],
js = ["jsi18n.js", "tesseract.min.js"] }
# Adding this javascript is crucial
def __init__(self, *args, **kwargs): js = ["jsi18n.js", "tesseract.min.js"]
if kwargs.get("instance"):
# We get the 'initial' keyword argument or initialize it def __init__(self, *args, **kwargs):
# as a dict if it didn't exist. self.user = kwargs.pop(
initial = kwargs.setdefault("initial", {}) "user"
# The widget for a ModelMultipleChoiceField expects ) # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
# a list of primary key for the selected data. if kwargs.get("instance"):
initial["case"] = [t.pk for t in kwargs["instance"].case.all()] # We get the 'initial' keyword argument or initialize it
# as a dict if it didn't exist.
super(SeriesForm, self).__init__(*args, **kwargs) initial = kwargs.setdefault("initial", {})
# self.fields["examination"] = ModelChoiceField( # The widget for a ModelMultipleChoiceField expects
# queryset=Examination.objects.all(), # a list of primary key for the selected data.
# widget=FilteredSelectMultiple(verbose_name="Examination", is_stacked=False), initial["case"] = [t.pk for t in kwargs["instance"].case.all()]
# )
super(SeriesForm, self).__init__(*args, **kwargs)
self.fields["modality"] = ModelChoiceField( # self.fields["examination"] = ModelChoiceField(
required=True, # queryset=Examination.objects.all(),
queryset=Modality.objects.all(), # widget=FilteredSelectMultiple(verbose_name="Examination", is_stacked=False),
) # )
ModelForm.__init__(self, *args, **kwargs) self.fields["modality"] = ModelChoiceField(
required=True,
case_queryset = Case.objects.all() queryset=Modality.objects.all(),
)
self.fields["case"] = ModelMultipleChoiceField(
required=False, ModelForm.__init__(self, *args, **kwargs)
queryset=case_queryset,
widget=FilteredSelectMultiple(verbose_name="Case", is_stacked=False), if self.user.groups.filter(name="atlas_editor").exists():
) case_queryset = Case.objects.all()
else:
def save(self, commit=True): case_queryset = Case.objects.filter(
# Get the unsaved Long instance author__id=self.user.id
instance = ModelForm.save(self, False) ) #| Case.objects.filter(open_access=True)
# Prepare a 'save_m2m' method for the form, self.fields["case"] = ModelMultipleChoiceField(
old_save_m2m = self.save_m2m required=False,
queryset=case_queryset,
def save_m2m(): widget=FilteredSelectMultiple(verbose_name="Case", is_stacked=False),
old_save_m2m() )
instance.case.clear()
for case in self.cleaned_data["case"]: def save(self, commit=True):
# We need the id here # Get the unsaved Long instance
instance.case.add(case.pk) instance = ModelForm.save(self, False)
self.save_m2m = save_m2m # Prepare a 'save_m2m' method for the form,
old_save_m2m = self.save_m2m
# Do we need to save all changes now?
# if commit: def save_m2m():
instance.save() old_save_m2m()
self.save_m2m() instance.case.clear()
for case in self.cleaned_data["case"]:
return instance # We need the id here
instance.case.add(case.pk)
class Meta:
model = Series self.save_m2m = save_m2m
exclude = ["author"]
# Do we need to save all changes now?
widgets = { # if commit:
"examination": autocomplete.ModelSelect2( instance.save()
url="generic:examination-autocomplete" self.save_m2m()
),
"description": Textarea(attrs={"maxlength": 1000, "rows": 5, "cols": 80}), return instance
}
class Meta:
model = Series
class CaseForm(ModelForm): exclude = ["author"]
# exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all(),widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False)) widgets = {
"examination": autocomplete.ModelSelect2(
class Media: url="generic:examination-autocomplete"
# Django also includes a few javascript files necessary ),
# for the operation of this form element. You need to "description": Textarea(attrs={"maxlength": 1000, "rows": 5, "cols": 80}),
# include <script src="/admin/jsi18n"></script> }
# in the template.
css = {
"all": ["css/widgets.css"], class CaseForm(ModelForm):
}
# Adding this javascript is crucial # exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all(),widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False))
js = ["jsi18n.js", "tesseract.min.js"]
class Media:
def __init__(self, *args, **kwargs): # Django also includes a few javascript files necessary
self.user = kwargs.pop( # for the operation of this form element. You need to
"user" # include <script src="/admin/jsi18n"></script>
) # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole # in the template.
if kwargs.get("instance"): css = {
# We get the 'initial' keyword argument or initialize it "all": ["css/widgets.css"],
# as a dict if it didn't exist. }
initial = kwargs.setdefault("initial", {}) # Adding this javascript is crucial
# The widget for a ModelMultipleChoiceField expects js = ["jsi18n.js", "tesseract.min.js"]
# a list of primary key for the selected data.
# initial["exams"] = [t.pk for t in kwargs["instance"].exams.all()] def __init__(self, *args, **kwargs):
self.user = kwargs.pop(
ModelForm.__init__(self, *args, **kwargs) "user"
) # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
super(CaseForm, self).__init__(*args, **kwargs) if kwargs.get("instance"):
# We get the 'initial' keyword argument or initialize it
class Meta: # as a dict if it didn't exist.
model = Case initial = kwargs.setdefault("initial", {})
# fields = ['due_back'] # The widget for a ModelMultipleChoiceField expects
# fields = '__all__' # a list of primary key for the selected data.
fields = [ # initial["exams"] = [t.pk for t in kwargs["instance"].exams.all()]
# "examination",
# "site", ModelForm.__init__(self, *args, **kwargs)
"title",
"subspecialty", super(CaseForm, self).__init__(*args, **kwargs)
"description", print(1)
"history",
"presentation", # self.fields["series"].queryset =
"discussion",
"condition", def get_queryset(self, request):
"pathological_process", return (
"report", super()
"open_access", .get_queryset(request)
"previous_case", .prefetch_related(
] "condition", "subspecialty", "pathological_process", "series"
# fields = ['question', 'findings', 'subspecialty', 'references'] )
widgets = { )
# "normal": RadioSelect(
# choices=[(True, 'Yes'), class Meta:
# (False, 'No')]) model = Case
# "findings": TinyMCE(attrs={"cols": 80, "rows": 20}), # fields = ['due_back']
# "mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}), # fields = '__all__'
"description": Textarea(attrs={"cols": 80, "rows": 5}), fields = [
"history": Textarea(attrs={"cols": 80, "rows": 5}), # "examination",
"discussion": Textarea(attrs={"cols": 80, "rows": 5}), # "site",
"condition": autocomplete.ModelSelect2Multiple( "title",
url="atlas:condition-autocomplete" "subspecialty",
), "description",
"presentation": autocomplete.ModelSelect2Multiple( "history",
url="atlas:presentation-autocomplete" "presentation",
), "discussion",
} "condition",
"pathological_process",
def save(self, commit=True): "report",
# Get the unsaved Case instance "open_access",
instance = ModelForm.save(self, False) "previous_case",
]
# Prepare a 'save_m2m' method for the form, # fields = ['question', 'findings', 'subspecialty', 'references']
old_save_m2m = self.save_m2m widgets = {
# "normal": RadioSelect(
def save_m2m(): # choices=[(True, 'Yes'),
old_save_m2m() # (False, 'No')])
# instance.exams.clear() # "findings": TinyMCE(attrs={"cols": 80, "rows": 20}),
# for exam in self.cleaned_data["exams"]: # "mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}),
# # We need the id here "description": Textarea(attrs={"cols": 80, "rows": 5}),
# instance.exams.add(exam.pk) "history": Textarea(attrs={"cols": 80, "rows": 5}),
"discussion": Textarea(attrs={"cols": 80, "rows": 5}),
self.save_m2m = save_m2m "condition": autocomplete.ModelSelect2Multiple(
url="atlas:condition-autocomplete"
# Do we need to save all changes now? ),
# if commit: "presentation": autocomplete.ModelSelect2Multiple(
instance.save() url="atlas:presentation-autocomplete"
self.save_m2m() ),
}
return instance
def save(self, commit=True):
# Get the unsaved Case instance
CaseDifferentialFormSet = inlineformset_factory( instance = ModelForm.save(self, False)
Case,
Differential, # Prepare a 'save_m2m' method for the form,
exclude=[], old_save_m2m = self.save_m2m
can_delete=True,
extra=1, def save_m2m():
max_num=10, old_save_m2m()
widgets={ # instance.exams.clear()
"condition": autocomplete.ModelSelect2(url="atlas:condition-autocomplete"), # for exam in self.cleaned_data["exams"]:
"text": Textarea(attrs={"maxlength": 1000, "rows": 3, "cols": 80}), # # We need the id here
}, # instance.exams.add(exam.pk)
)
self.save_m2m = save_m2m
SeriesFormSet = inlineformset_factory(
Case, # Do we need to save all changes now?
Series.case.through, # if commit:
exclude=[], instance.save()
can_delete=True, self.save_m2m()
extra=0,
max_num=10, return instance
field_classes="testing",
)
CaseDifferentialFormSet = inlineformset_factory(
Case,
SeriesImageFormSet = inlineformset_factory( Differential,
Series, exclude=[],
SeriesImage, can_delete=True,
exclude=[], extra=1,
can_delete=True, max_num=10,
extra=0, widgets={
max_num=2000, "condition": autocomplete.ModelSelect2(url="atlas:condition-autocomplete"),
field_classes="testing", "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,
)
+4
View File
@@ -400,6 +400,10 @@ class Series(models.Model):
) )
def __str__(self): def __str__(self):
return f"{self.pk}:{self.description}"
def get_full_str(self):
if self.case: if self.case:
case_id = ", ".format([case.pk for case in self.case.all()]) case_id = ", ".format([case.pk for case in self.case.all()])
# case_id = self.case.pk # case_id = self.case.pk
+55 -26
View File
@@ -1,52 +1,81 @@
{% extends 'atlas/base.html' %} {% extends 'atlas/base.html' %}
{% block content %} {% block content %}
<h2>Case {{case_number|add:1}}</h2> <h2>Case {{case_number|add:1}}
<div class="pre-whitespace multi-image-block"> {% if collection.show_title %}
{% for series in series_list %} : {{case.title}}
<span class="series-block"> {% endif %}
<span>
Series {{ forloop.counter }}: </h2>
<a href="#" onclick='window.loadDicomViewer(window.images[{{forloop.counter0}}])'>
{{series.get_block}} {% if collection.show_description and case.description%}
</a> <div>
</span> Description: {{case.description}}
</span> </div>
{% endfor %} {% endif %}
<div class="pre-whitespace multi-image-block">
{% for series in series_list %}
<span class="series-block">
<span>
Series {{ forloop.counter }}:
<a href="#" onclick='window.loadDicomViewer(window.images[{{forloop.counter0}}])'>
{{series.get_block}}
</a>
</span>
</span>
{% endfor %}
</div>
<div>
<div id="single-dicom-viewer" class="dicom-viewer" data-images="" data-annotations=''>
</div> </div>
<div>
<div id="single-dicom-viewer" class="dicom-viewer" data-images="" data-annotations=''>
</div>
</div> </div>
{% if collection.show_discussion and case.discussion%}
<details>
<summary>
Discussion:
</summary>
<div>
{{case.discussion}}
</div>
</details>
{% endif %}
<div> <div>
{% if previous %} {% if previous %}
<a href="{% url 'atlas:collection_case_view' pk=collection.pk case_number=case_number|add:-1 %}">Previous</a> <a href="{% url 'atlas:collection_case_view' pk=collection.pk case_number=case_number|add:-1 %}">Previous</a>
{% endif %} {% endif %}
{% if next %} {% if next %}
<a href="{% url 'atlas:collection_case_view' pk=collection.pk case_number=case_number|add:1 %}">Next</a> <a href="{% url 'atlas:collection_case_view' pk=collection.pk case_number=case_number|add:1 %}">Next</a>
{% endif %} {% endif %}
</div> </div>
<br/> <br />
Return to <a href='{{collection.get_absolute_url}}'>collection</a> Return to <a href='{{collection.get_absolute_url}}'>collection</a>
{% endblock %} {% endblock %}
{% block js %} {% block js %}
<script type="text/javascript"> <script type="text/javascript">
window.images = { window.images = {
{% for series in series_list %} {
{{forloop.counter0}} : ["{{ series.get_image_url_array_not_json }}"], %
{% endfor %} for series in series_list %
} {
{
forloop.counter0
}
}: ["{{ series.get_image_url_array_not_json }}"],
{
% endfor %
}
} }
$(document).ready(function () { $(document).ready(function () {
setTimeout(() => { setTimeout(() => {
window.loadDicomViewer(window.images[0]) window.loadDicomViewer(window.images[0])
}, 500); }, 500);
}) })
</script> </script>
{% endblock js %} {% endblock js %}
@@ -4,7 +4,11 @@
<h2>{{collection.name}} <h2>{{collection.name}}
<ul> <ul>
{% for case in collection.cases.all %} {% for case in collection.cases.all %}
<li><a href="{% url 'atlas:collection_case_view' pk=collection.pk case_number=forloop.counter0 %}">Case {{forloop.counter}}</a></li> <li><a href="{% url 'atlas:collection_case_view' pk=collection.pk case_number=forloop.counter0 %}">Case {{forloop.counter}}</a>
{% if collection.show_title %}
: {{case.title}}
{% endif %}
</li>
{% endfor %} {% endfor %}
+14 -3
View File
@@ -363,6 +363,11 @@ class SeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView):
return initial 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): def get_context_data(self, **kwargs):
context = super(SeriesCreate, self).get_context_data(**kwargs) context = super(SeriesCreate, self).get_context_data(**kwargs)
@@ -416,6 +421,11 @@ class SeriesUpdate(
context["image_formset"] = SeriesImageFormSet(instance=self.object) context["image_formset"] = SeriesImageFormSet(instance=self.object)
return context 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): def form_valid(self, form):
self.object = form.save(commit=False) self.object = form.save(commit=False)
@@ -484,7 +494,7 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin):
context = super(AtlasCreateBase, self).get_context_data(**kwargs) context = super(AtlasCreateBase, self).get_context_data(**kwargs)
if self.request.POST: if self.request.POST:
context["series_formset"] = SeriesFormSet( 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( context["casedifferential_formset"] = CaseDifferentialFormSet(
self.request.POST, self.request.FILES self.request.POST, self.request.FILES
@@ -492,6 +502,7 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin):
context["series_formset"].full_clean() context["series_formset"].full_clean()
context["casedifferential_formset"].full_clean() context["casedifferential_formset"].full_clean()
else: 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["series_formset"] = SeriesFormSet()
context["casedifferential_formset"] = CaseDifferentialFormSet() context["casedifferential_formset"] = CaseDifferentialFormSet()
return context return context
@@ -558,7 +569,7 @@ class AtlasUpdate(
context = super(AtlasUpdate, self).get_context_data(**kwargs) context = super(AtlasUpdate, self).get_context_data(**kwargs)
if self.request.POST: if self.request.POST:
context["series_formset"] = SeriesFormSet( 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( context["casedifferential_formset"] = CaseDifferentialFormSet(
self.request.POST, self.request.FILES, instance=self.object self.request.POST, self.request.FILES, instance=self.object
@@ -566,7 +577,7 @@ class AtlasUpdate(
context["series_formset"].full_clean() context["series_formset"].full_clean()
context["casedifferential_formset"].full_clean() context["casedifferential_formset"].full_clean()
else: 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( context["casedifferential_formset"] = CaseDifferentialFormSet(
instance=self.object instance=self.object
) )