further improvements

This commit is contained in:
Ross
2023-08-14 14:30:01 +01:00
parent cc2cbde691
commit a4e66696bd
8 changed files with 139 additions and 49 deletions
+24 -5
View File
@@ -32,6 +32,11 @@ class SeriesSchema(ModelSchema):
def resolve_case_id(obj): def resolve_case_id(obj):
return [i.id for i in obj.case.all()] return [i.id for i in obj.case.all()]
class CaseSchema(ModelSchema):
class Config:
model = Case
model_fields = ["id", "title"]
@router.post("/upload_dicom", auth=django_auth) @router.post("/upload_dicom", auth=django_auth)
def upload_dicom(request, files: List[UploadedFile] = File(...)): def upload_dicom(request, files: List[UploadedFile] = File(...)):
@@ -73,9 +78,7 @@ def uncategorised_dicoms(request):
return data return data
def import_dicoms_helper(request, case_id: int | None=None):
@router.get("/import_dicoms", auth=django_auth, response=List[SeriesSchema])
def import_dicoms(request):
dicoms = UncategorisedDicom.objects.filter(user=request.user) dicoms = UncategorisedDicom.objects.filter(user=request.user)
data = defaultdict(list) data = defaultdict(list)
@@ -104,16 +107,30 @@ def import_dicoms(request):
# We might only want to add the author during creation.... # We might only want to add the author during creation....
series.author.add(request.user) series.author.add(request.user)
if case_id is not None:
series.case.add(case_id)
for dicom, dicom_tags in data[series_uid]: for dicom, dicom_tags in data[series_uid]:
series_image = SeriesImage(image=dicom.image, series=series) series_image = SeriesImage(image=dicom.image, series=series)
series_image.save() series_image.save()
dicom.image.delete() #dicom.image.delete()
dicom.delete() dicom.delete()
series_list.append(series) series_list.append(series)
return series_list return series_list
@router.get("/import_dicoms", auth=django_auth, response=List[SeriesSchema])
def import_dicoms(request):
return import_dicoms_helper(request)
@router.get("/import_dicoms/{case_id}", auth=django_auth, response=List[SeriesSchema])
def import_dicoms_case(request, case_id: int):
return import_dicoms_helper(request, case_id=case_id)
@router.get("/orphan_series", auth=django_auth, response=List[SeriesSchema]) @router.get("/orphan_series", auth=django_auth, response=List[SeriesSchema])
def orphan_series(request): def orphan_series(request):
#print(request.user.series.filter(case=None)) #print(request.user.series.filter(case=None))
@@ -137,4 +154,6 @@ def series_remove_duplicate_images(request, series_id: int):
return len(dupes) return len(dupes)
@router.get("/get_cases_user", auth=django_auth, response=List[CaseSchema])
def get_cases_user(request):
return Case.objects.filter(author=request.user)
@@ -0,0 +1,19 @@
# Generated by Django 4.1.4 on 2023-08-14 12:31
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('atlas', '0014_series_series_instance_uid_alter_series_examination_and_more'),
]
operations = [
migrations.AlterField(
model_name='seriesimage',
name='series',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='images', to='atlas.series'),
),
]
+2 -1
View File
@@ -392,6 +392,7 @@ def extract_image_dicom_json_from_ds(ds, url, image_index):
else: else:
d[key] = val d[key] = val
# Is it worth trying on fake dicom tags?.....
if d == {}: if d == {}:
d["SOPInstanceUID"] = f"1.2.840.1111.{image_index}" d["SOPInstanceUID"] = f"1.2.840.1111.{image_index}"
d["SeriesInstanceUID"] = f"1.2.840.1112.1" d["SeriesInstanceUID"] = f"1.2.840.1112.1"
@@ -402,7 +403,7 @@ def extract_image_dicom_json_from_ds(ds, url, image_index):
class SeriesImage(SeriesImageBase): class SeriesImage(SeriesImageBase):
image = models.FileField(upload_to=image_directory_path) image = models.FileField(upload_to=image_directory_path)
series = models.ForeignKey( series = models.ForeignKey(
"Series", related_name="images", on_delete=models.SET_NULL, null=True "Series", related_name="images", on_delete=models.CASCADE, null=True
) )
def get_dicom_data(self): def get_dicom_data(self):
+25 -14
View File
@@ -1,36 +1,47 @@
{% extends 'atlas/base.html' %} {% extends 'atlas/base.html' %}
{% block content %} {% block content %}
<h2>Uploaded dicoms</h2> <h2>Uploaded dicoms</h2>
{% if dicoms %} {% if series_list %}
<ul> <ul>
{% for dicom in dicoms %} {% for series, n, tags in series_list %}
<li> <li>
{{dicom.image}} {{dicom.get_basic_dicom_tags}} {{series}} [{{n}} images] <br/>
{{tags}}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% if case %}
<p>Importing into case {{case}}</p>
{% endif %}
<button <button
hx-get="{% url 'api-1:clear_dicoms' %}" hx-get="{% url 'api-1:clear_dicoms' %}"
hx-confirm="This will clear all uploads that have not been imported into series, Continue?" hx-confirm="This will clear all uploads that have not been imported into series, Continue?"
>Delete Uploads</button> >Delete Uploads</button>
<button {% if case %}
hx-get="{% url 'api-1:import_dicoms' %}" <button
hx-target=".imported" hx-get="{% url 'api-1:import_dicoms_case' case.id %}"
hx-target=".imported"
>Import</button>
>Import</button> {% else %}
<button
hx-get="{% url 'api-1:import_dicoms' %}"
hx-target=".imported"
>Import</button>
{% endif %}
<div class="imported"> <div class="imported">
</div> </div>
{% else %} {% else %}
No uploads awaiting importing have been found. No uploads awaiting importing have been found.
{% endif %} {% endif %}
<p><a href="{% url 'atlas:series_view' %}?case=null">View orphan series</a></p> <p><a href="{% url 'atlas:series_view' %}?case=null">View orphan series</a></p>
{% endblock %} {% endblock %}
+1
View File
@@ -35,6 +35,7 @@ urlpatterns = [
path("collection/", views.CollectionView.as_view(), name="collection_view"), path("collection/", views.CollectionView.as_view(), name="collection_view"),
path("collection/user", views.user_collections, name="user_collections"), path("collection/user", views.user_collections, name="user_collections"),
path("uploads", views.user_uploads, name="user_uploads"), path("uploads", views.user_uploads, name="user_uploads"),
path("uploads/case/<int:case_id>", views.user_uploads, name="user_uploads"),
path( path(
"collection/create", "collection/create",
views.CaseCollectionCreate.as_view(), views.CaseCollectionCreate.as_view(),
+37 -17
View File
@@ -291,18 +291,39 @@ def author_list(request):
return render(request, "atlas/author_list.html", {"authors": authors}) return render(request, "atlas/author_list.html", {"authors": authors})
def index(request): def index(request):
return render(request, "atlas/index.html", {}) return render(request, "atlas/index.html", {})
def user_collections(request): def user_collections(request):
collections = request.user.user_casecollection_exams.all() collections = request.user.user_casecollection_exams.all()
return render(request, "atlas/user_collections.html", {"collections": collections}) return render(request, "atlas/user_collections.html", {"collections": collections})
def user_uploads(request):
def user_uploads(request, case_id: int | None = None):
dicoms = UncategorisedDicom.objects.filter(user=request.user) dicoms = UncategorisedDicom.objects.filter(user=request.user)
return render(request, "atlas/user_uploads.html", {"dicoms": dicoms}) data = defaultdict(list)
for d in dicoms:
tags = d.get_basic_dicom_tags()
data[tags["SeriesInstanceUID"]].append(tags)
series_list = []
for series in data:
series_list.append((series, len(data[series]), data[series][0]))
print(series_list)
case = False
if case_id is not None:
case = get_object_or_404(Case, pk=case_id)
return render(
request, "atlas/user_uploads.html", {"series_list": series_list, "case": case}
)
class CaseDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView): class CaseDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView):
model = Case model = Case
@@ -1320,7 +1341,6 @@ def collection_take_overview(
else: else:
raise Http404() raise Http404()
cases = collection.cases.all().order_by("casedetail__sort_order").prefetch_related() cases = collection.cases.all().order_by("casedetail__sort_order").prefetch_related()
case_details = CaseDetail.objects.filter(case__in=cases, collection=collection) case_details = CaseDetail.objects.filter(case__in=cases, collection=collection)
@@ -1361,7 +1381,6 @@ def collection_take_overview(
) )
def collection_case_view_take_user(request, pk: int, case_number: int): def collection_case_view_take_user(request, pk: int, case_number: int):
return collection_case_view_take(request, pk, case_number) return collection_case_view_take(request, pk, case_number)
@@ -1402,9 +1421,7 @@ def collection_case_view_take(
cid_user_exam.start_time = timezone.now() cid_user_exam.start_time = timezone.now()
cid_user_exam.save() cid_user_exam.save()
if not collection.review_only(): if not collection.review_only():
if collection.collection_type == "REP": if collection.collection_type == "REP":
case_detail = CaseDetail.objects.get(case=case, collection=collection) case_detail = CaseDetail.objects.get(case=case, collection=collection)
@@ -1419,7 +1436,6 @@ def collection_case_view_take(
if request.method == "POST": if request.method == "POST":
if collection.collection_type == "REP": if collection.collection_type == "REP":
if not collection.publish_results: if not collection.publish_results:
if answer: if answer:
form = ReportAnswerForm(request.POST, instance=answer) form = ReportAnswerForm(request.POST, instance=answer)
@@ -1534,7 +1550,6 @@ def collection_case_view(request, pk, case_number):
form = None form = None
answer = None answer = None
case, case_count = collection.get_case_by_index(case_number, case_count=True) case, case_count = collection.get_case_by_index(case_number, case_count=True)
series_list = case.series.all().prefetch_related("images", "examination", "plane") series_list = case.series.all().prefetch_related("images", "examination", "plane")
@@ -1558,11 +1573,13 @@ def collection_case_view(request, pk, case_number):
}, },
) )
def case_dicom_json(request, pk): def case_dicom_json(request, pk):
case = get_object_or_404(Case, pk=pk) case = get_object_or_404(Case, pk=pk)
return JsonResponse(case.get_case_dicom_json()) return JsonResponse(case.get_case_dicom_json())
@user_is_collection_author_or_atlas_editor @user_is_collection_author_or_atlas_editor
def delete_collection_cid_answers(request, exam_id, cid): def delete_collection_cid_answers(request, exam_id, cid):
collection = get_object_or_404(CaseCollection, pk=exam_id) collection = get_object_or_404(CaseCollection, pk=exam_id)
@@ -1755,6 +1772,7 @@ GenericExamViews = ExamViews(
CaseCollection, Case, None, CidReportAnswer, "atlas", "casecollection" CaseCollection, Case, None, CidReportAnswer, "atlas", "casecollection"
) )
class CollectionCloneMixin: class CollectionCloneMixin:
def get_initial(self): def get_initial(self):
old_object = get_object_or_404(self.model, pk=self.kwargs["exam_id"]) old_object = get_object_or_404(self.model, pk=self.kwargs["exam_id"])
@@ -1777,13 +1795,15 @@ class CollectionCloneMixin:
object.save() object.save()
return HttpResponseRedirect(object.get_absolute_url()) return HttpResponseRedirect(object.get_absolute_url())
class CollectionClone(CollectionCloneMixin, CaseCollectionCreate): class CollectionClone(CollectionCloneMixin, CaseCollectionCreate):
"""Clone exam view""" """Clone exam view"""
class SelfReviewDelete(DeleteView): class SelfReviewDelete(DeleteView):
model = SelfReview model = SelfReview
template_name = "confirm_delete.html" template_name = "confirm_delete.html"
#success_url = reverse_lazy("atlas:finding_view") # success_url = reverse_lazy("atlas:finding_view")
def get_initial(self): def get_initial(self):
user_exam_id = self.kwargs["user_exam_id"] user_exam_id = self.kwargs["user_exam_id"]
@@ -1806,9 +1826,8 @@ class SelfReviewDelete(DeleteView):
def get_success_url(self) -> str: def get_success_url(self) -> str:
return self.user_exam.exam.get_case_take_url(self.case) return self.user_exam.exam.get_case_take_url(self.case)
class SelfReviewUpdate(
UpdateView class SelfReviewUpdate(UpdateView):
):
model = SelfReview model = SelfReview
form_class = SelfReviewForm form_class = SelfReviewForm
@@ -1833,10 +1852,10 @@ class SelfReviewUpdate(
def get_success_url(self) -> str: def get_success_url(self) -> str:
return self.user_exam.exam.get_case_take_url(self.case) return self.user_exam.exam.get_case_take_url(self.case)
#def get_object(self): # def get_object(self):
# return self.review # return self.review
# return # return
#def get_initial(self): # def get_initial(self):
# user_exam_id = self.kwargs["user_exam_id"] # user_exam_id = self.kwargs["user_exam_id"]
# case_id = self.kwargs["case_id"] # case_id = self.kwargs["case_id"]
@@ -1844,6 +1863,7 @@ class SelfReviewUpdate(
# self.case = get_object_or_404(Case, pk=case_id) # self.case = get_object_or_404(Case, pk=case_id)
# return {"user_exam": user_exam_id, "case": case_id} # return {"user_exam": user_exam_id, "case": case_id}
class AddSelfReview(CreateView): class AddSelfReview(CreateView):
model = SelfReview model = SelfReview
form_class = SelfReviewForm form_class = SelfReviewForm
@@ -1854,7 +1874,7 @@ class AddSelfReview(CreateView):
kwargs = super(AddSelfReview, self).get_form_kwargs() kwargs = super(AddSelfReview, self).get_form_kwargs()
# update the kwargs for the form init method with yours # update the kwargs for the form init method with yours
kwargs.update(self.kwargs) # self.kwargs contains all url conf params kwargs.update(self.kwargs) # self.kwargs contains all url conf params
#kwargs.update({"user": self.request.user}) # kwargs.update({"user": self.request.user})
return kwargs return kwargs
def get_initial(self): def get_initial(self):
@@ -1874,7 +1894,8 @@ class AddSelfReview(CreateView):
def get_success_url(self) -> str: def get_success_url(self) -> str:
return self.user_exam.exam.get_case_take_url(self.case) return self.user_exam.exam.get_case_take_url(self.case)
#return reverse("atlas:collection_take_overview_user", kwargs={"pk": self.user_exam.collection.id }) # return reverse("atlas:collection_take_overview_user", kwargs={"pk": self.user_exam.collection.id })
# def form_valid(self, form): # def form_valid(self, form):
# model = form.save(commit=False) # model = form.save(commit=False)
@@ -1892,7 +1913,6 @@ def uncategorised_dicoms(request):
data = [] data = []
for d in dicoms: for d in dicoms:
data.append((d.image.name, d.get_basic_dicom_tags())) data.append((d.image.name, d.get_basic_dicom_tags()))
return JsonResponse(data, safe=False) return JsonResponse(data, safe=False)
@@ -0,0 +1,19 @@
# Generated by Django 4.1.4 on 2023-08-14 12:31
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('longs', '0007_longseriesimage_image_md5_hash_and_more'),
]
operations = [
migrations.AlterField(
model_name='longseriesimage',
name='series',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='images', to='longs.longseries'),
),
]
+1 -1
View File
@@ -354,7 +354,7 @@ def test_image_validator(file):
class LongSeriesImage(SeriesImageBase): class LongSeriesImage(SeriesImageBase):
image = models.FileField(upload_to=image_directory_path) image = models.FileField(upload_to=image_directory_path)
series = models.ForeignKey( series = models.ForeignKey(
"LongSeries", related_name="images", on_delete=models.SET_NULL, null=True "LongSeries", related_name="images", on_delete=models.CASCADE, null=True
) )