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.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 <script src="/admin/jsi18n"></script>
# 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 <script src="/admin/jsi18n"></script>
# 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 <script src="/admin/jsi18n"></script>
# 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 <script src="/admin/jsi18n"></script>
# 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,
)
+4
View File
@@ -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
+55 -26
View File
@@ -1,52 +1,81 @@
{% extends 'atlas/base.html' %}
{% block content %}
<h2>Case {{case_number|add:1}}</h2>
<h2>Case {{case_number|add:1}}
<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 %}
{% if collection.show_title %}
: {{case.title}}
{% endif %}
</h2>
{% if collection.show_description and case.description%}
<div>
Description: {{case.description}}
</div>
{% 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 id="single-dicom-viewer" class="dicom-viewer" data-images="" data-annotations=''>
</div>
</div>
{% if collection.show_discussion and case.discussion%}
<details>
<summary>
Discussion:
</summary>
<div>
{{case.discussion}}
</div>
</details>
{% endif %}
<div>
{% if previous %}
{% if previous %}
<a href="{% url 'atlas:collection_case_view' pk=collection.pk case_number=case_number|add:-1 %}">Previous</a>
{% endif %}
{% if next %}
{% endif %}
{% if next %}
<a href="{% url 'atlas:collection_case_view' pk=collection.pk case_number=case_number|add:1 %}">Next</a>
{% endif %}
{% endif %}
</div>
<br/>
<br />
Return to <a href='{{collection.get_absolute_url}}'>collection</a>
{% endblock %}
{% block js %}
<script type="text/javascript">
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 () {
setTimeout(() => {
window.loadDicomViewer(window.images[0])
window.loadDicomViewer(window.images[0])
}, 500);
})
</script>
{% endblock js %}
@@ -4,7 +4,11 @@
<h2>{{collection.name}}
<ul>
{% 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 %}
+14 -3
View File
@@ -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
)