.
This commit is contained in:
+13
-5
@@ -1,5 +1,13 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Case, Series, SeriesImage, Condition, Subspecialty, Finding, SeriesFindings
|
from .models import (
|
||||||
|
Case,
|
||||||
|
Series,
|
||||||
|
SeriesImage,
|
||||||
|
Condition,
|
||||||
|
Subspecialty,
|
||||||
|
Finding,
|
||||||
|
SeriesFinding,
|
||||||
|
)
|
||||||
|
|
||||||
import tagulous.admin
|
import tagulous.admin
|
||||||
|
|
||||||
@@ -20,7 +28,7 @@ admin.site.register(SeriesImage)
|
|||||||
admin.site.register(Condition)
|
admin.site.register(Condition)
|
||||||
admin.site.register(Subspecialty)
|
admin.site.register(Subspecialty)
|
||||||
admin.site.register(Finding)
|
admin.site.register(Finding)
|
||||||
admin.site.register(SeriesFindings)
|
admin.site.register(SeriesFinding)
|
||||||
|
|
||||||
|
|
||||||
class AtlasAdminForm(ModelForm):
|
class AtlasAdminForm(ModelForm):
|
||||||
@@ -31,7 +39,7 @@ class AtlasAdminForm(ModelForm):
|
|||||||
"description",
|
"description",
|
||||||
"history",
|
"history",
|
||||||
"sign",
|
"sign",
|
||||||
#"findings",
|
# "findings",
|
||||||
"author",
|
"author",
|
||||||
"series",
|
"series",
|
||||||
]
|
]
|
||||||
@@ -40,8 +48,8 @@ class AtlasAdminForm(ModelForm):
|
|||||||
# "normal": RadioSelect(
|
# "normal": RadioSelect(
|
||||||
# choices=[(True, 'Yes'),
|
# choices=[(True, 'Yes'),
|
||||||
# (False, 'No')])
|
# (False, 'No')])
|
||||||
#"findings": TinyMCE(attrs={"cols": 80, "rows": 30}),
|
# "findings": TinyMCE(attrs={"cols": 80, "rows": 30}),
|
||||||
#"mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}),
|
# "mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+9
-13
@@ -8,12 +8,7 @@ from django.forms import (
|
|||||||
)
|
)
|
||||||
from django.forms import inlineformset_factory
|
from django.forms import inlineformset_factory
|
||||||
|
|
||||||
from atlas.models import (
|
from atlas.models import Case, Series, SeriesImage, SeriesFinding
|
||||||
Case,
|
|
||||||
Series,
|
|
||||||
SeriesImage,
|
|
||||||
SeriesFindings
|
|
||||||
)
|
|
||||||
|
|
||||||
from anatomy.models import Modality
|
from anatomy.models import Modality
|
||||||
|
|
||||||
@@ -33,9 +28,9 @@ class ExaminationForm(ModelForm):
|
|||||||
fields = ["examination"]
|
fields = ["examination"]
|
||||||
|
|
||||||
|
|
||||||
class SeriesFindingsForm(ModelForm):
|
class SeriesFindingForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SeriesFindings
|
model = SeriesFinding
|
||||||
exclude = ["series", "annotation_json"]
|
exclude = ["series", "annotation_json"]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -47,10 +42,11 @@ class SeriesFindingsForm(ModelForm):
|
|||||||
# a list of primary key for the selected data.
|
# a list of primary key for the selected data.
|
||||||
initial["series"] = kwargs.pop("series_id")
|
initial["series"] = kwargs.pop("series_id")
|
||||||
|
|
||||||
super(SeriesFindingsForm, self).__init__(*args, **kwargs)
|
super(SeriesFindingForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
ModelForm.__init__(self, *args, **kwargs)
|
ModelForm.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class SeriesForm(ModelForm):
|
class SeriesForm(ModelForm):
|
||||||
class Media:
|
class Media:
|
||||||
# Django also includes a few javascript files necessary
|
# Django also includes a few javascript files necessary
|
||||||
@@ -163,9 +159,9 @@ class CaseForm(ModelForm):
|
|||||||
"subspecialty",
|
"subspecialty",
|
||||||
"description",
|
"description",
|
||||||
"history",
|
"history",
|
||||||
#"findings",
|
# "findings",
|
||||||
"condition",
|
"condition",
|
||||||
#"sign",
|
# "sign",
|
||||||
"open_access",
|
"open_access",
|
||||||
]
|
]
|
||||||
# fields = ['question', 'findings', 'subspecialty', 'references']
|
# fields = ['question', 'findings', 'subspecialty', 'references']
|
||||||
@@ -173,8 +169,8 @@ class CaseForm(ModelForm):
|
|||||||
# "normal": RadioSelect(
|
# "normal": RadioSelect(
|
||||||
# choices=[(True, 'Yes'),
|
# choices=[(True, 'Yes'),
|
||||||
# (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}),
|
||||||
"description": Textarea(attrs={"cols": 80, "rows": 5}),
|
"description": Textarea(attrs={"cols": 80, "rows": 5}),
|
||||||
"history": Textarea(attrs={"cols": 80, "rows": 5}),
|
"history": Textarea(attrs={"cols": 80, "rows": 5}),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,42 +8,80 @@ import django.db.models.deletion
|
|||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('atlas', '0006_auto_20211128_1448'),
|
("atlas", "0006_auto_20211128_1448"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Finding',
|
name="Finding",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
('name', models.CharField(max_length=255)),
|
"id",
|
||||||
('primary_name', models.BooleanField(default='True')),
|
models.BigAutoField(
|
||||||
('synonym', models.ManyToManyField(blank=True, related_name='_atlas_finding_synonym_+', to='atlas.Finding')),
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=255)),
|
||||||
|
("primary_name", models.BooleanField(default="True")),
|
||||||
|
(
|
||||||
|
"synonym",
|
||||||
|
models.ManyToManyField(
|
||||||
|
blank=True,
|
||||||
|
related_name="_atlas_finding_synonym_+",
|
||||||
|
to="atlas.Finding",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
bases=(atlas.models.SynMixin, models.Model),
|
bases=(atlas.models.SynMixin, models.Model),
|
||||||
),
|
),
|
||||||
migrations.RemoveField(
|
migrations.RemoveField(
|
||||||
model_name='case',
|
model_name="case",
|
||||||
name='findings',
|
name="findings",
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='case',
|
model_name="case",
|
||||||
name='description',
|
name="description",
|
||||||
field=models.TextField(blank=True, help_text='Description of the case'),
|
field=models.TextField(blank=True, help_text="Description of the case"),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='series',
|
model_name="series",
|
||||||
name='description',
|
name="description",
|
||||||
field=models.TextField(blank=True, help_text='Description of stack'),
|
field=models.TextField(blank=True, help_text="Description of stack"),
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='SeriesFindings',
|
name="SeriesFinding",
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
(
|
||||||
('description', models.TextField(blank=True, help_text='Findings on the series / stack', null=True)),
|
"id",
|
||||||
('annotation_json', models.TextField(blank=True, null=True)),
|
models.BigAutoField(
|
||||||
('findings', models.ManyToManyField(blank=True, to='atlas.Finding')),
|
auto_created=True,
|
||||||
('series', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='findings', to='atlas.series')),
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"description",
|
||||||
|
models.TextField(
|
||||||
|
blank=True,
|
||||||
|
help_text="Findings on the series / stack",
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("annotation_json", models.TextField(blank=True, null=True)),
|
||||||
|
("findings", models.ManyToManyField(blank=True, to="atlas.Finding")),
|
||||||
|
(
|
||||||
|
"series",
|
||||||
|
models.ForeignKey(
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="findings",
|
||||||
|
to="atlas.series",
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
+15
-7
@@ -73,8 +73,9 @@ def findMiddle(input_list):
|
|||||||
return input_list[int(middle)]
|
return input_list[int(middle)]
|
||||||
return (input_list[int(middle)], input_list[int(middle - 1)])
|
return (input_list[int(middle)], input_list[int(middle - 1)])
|
||||||
|
|
||||||
|
|
||||||
class SynMixin(object):
|
class SynMixin(object):
|
||||||
#class Meta:
|
# class Meta:
|
||||||
# abstract = True
|
# abstract = True
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
@@ -94,6 +95,7 @@ class Finding(SynMixin, models.Model):
|
|||||||
|
|
||||||
primary_name = models.BooleanField(default="True")
|
primary_name = models.BooleanField(default="True")
|
||||||
|
|
||||||
|
|
||||||
class Condition(SynMixin, models.Model):
|
class Condition(SynMixin, models.Model):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
@@ -103,15 +105,17 @@ class Condition(SynMixin, models.Model):
|
|||||||
|
|
||||||
subspecialty = models.ManyToManyField("subspecialty", blank=True)
|
subspecialty = models.ManyToManyField("subspecialty", blank=True)
|
||||||
|
|
||||||
|
|
||||||
class Subspecialty(models.Model):
|
class Subspecialty(models.Model):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
class Case(models.Model):
|
class Case(models.Model):
|
||||||
#class SubspecialtyChoices(models.TextChoices):
|
# class SubspecialtyChoices(models.TextChoices):
|
||||||
# BREAST = "BR", _("Breast")
|
# BREAST = "BR", _("Breast")
|
||||||
# CARDIAC = "CA", _("Cardiac")
|
# CARDIAC = "CA", _("Cardiac")
|
||||||
# GASTRO = "GI", _("Gastrointestinal and hepatobiliary")
|
# GASTRO = "GI", _("Gastrointestinal and hepatobiliary")
|
||||||
@@ -134,9 +138,9 @@ class Case(models.Model):
|
|||||||
|
|
||||||
history = models.TextField(null=True, blank=True)
|
history = models.TextField(null=True, blank=True)
|
||||||
|
|
||||||
#findings = models.TextField(null=True, blank=True)
|
# findings = models.TextField(null=True, blank=True)
|
||||||
|
|
||||||
#subspecialty = models.CharField(max_length=2, choices=SubspecialtyChoices.choices)
|
# subspecialty = models.CharField(max_length=2, choices=SubspecialtyChoices.choices)
|
||||||
subspecialty = models.ManyToManyField(Subspecialty, blank=True)
|
subspecialty = models.ManyToManyField(Subspecialty, blank=True)
|
||||||
|
|
||||||
condition = models.ManyToManyField(Condition, blank=True)
|
condition = models.ManyToManyField(Condition, blank=True)
|
||||||
@@ -205,18 +209,22 @@ class SeriesImage(models.Model):
|
|||||||
info = "File is not a dicom."
|
info = "File is not a dicom."
|
||||||
return info
|
return info
|
||||||
|
|
||||||
class SeriesFindings(models.Model):
|
|
||||||
|
class SeriesFinding(models.Model):
|
||||||
|
|
||||||
series = models.ForeignKey(
|
series = models.ForeignKey(
|
||||||
"Series", related_name="findings", on_delete=models.SET_NULL, null=True
|
"Series", related_name="findings", on_delete=models.SET_NULL, null=True
|
||||||
)
|
)
|
||||||
description = models.TextField(null=True, blank=True, help_text="Findings on the series / stack")
|
description = models.TextField(
|
||||||
|
null=True, blank=True, help_text="Findings on the series / stack"
|
||||||
|
)
|
||||||
findings = models.ManyToManyField(Finding, blank=True)
|
findings = models.ManyToManyField(Finding, blank=True)
|
||||||
annotation_json = models.TextField(null=True, blank=True)
|
annotation_json = models.TextField(null=True, blank=True)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"{self.series.id}/{self.description}"
|
return f"{self.series.id}/{self.description}"
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
class Series(models.Model):
|
class Series(models.Model):
|
||||||
modality = models.ForeignKey(
|
modality = models.ForeignKey(
|
||||||
@@ -259,7 +267,7 @@ class Series(models.Model):
|
|||||||
related_name="series",
|
related_name="series",
|
||||||
)
|
)
|
||||||
|
|
||||||
#findings = models.TextField(null=True, blank=True, help_text="Findings on the series / stack")
|
# findings = models.TextField(null=True, blank=True, help_text="Findings on the series / stack")
|
||||||
|
|
||||||
open_access = models.BooleanField(
|
open_access = models.BooleanField(
|
||||||
help_text="If a question should be freely available to browse", default=True
|
help_text="If a question should be freely available to browse", default=True
|
||||||
|
|||||||
+22
-19
@@ -30,7 +30,7 @@ from .forms import (
|
|||||||
SeriesImageFormSet,
|
SeriesImageFormSet,
|
||||||
SeriesFormSet,
|
SeriesFormSet,
|
||||||
ExaminationForm,
|
ExaminationForm,
|
||||||
SeriesFindingsForm
|
SeriesFindingForm,
|
||||||
)
|
)
|
||||||
from .models import (
|
from .models import (
|
||||||
Case,
|
Case,
|
||||||
@@ -38,8 +38,8 @@ from .models import (
|
|||||||
Examination,
|
Examination,
|
||||||
Finding,
|
Finding,
|
||||||
Subspecialty,
|
Subspecialty,
|
||||||
SeriesFindings,
|
SeriesFinding,
|
||||||
SeriesImage
|
SeriesImage,
|
||||||
)
|
)
|
||||||
from .tables import AtlasTable, SeriesTable
|
from .tables import AtlasTable, SeriesTable
|
||||||
from .filters import AtlasFilter, SeriesFilter
|
from .filters import AtlasFilter, SeriesFilter
|
||||||
@@ -117,11 +117,14 @@ def series_detail(request, pk):
|
|||||||
|
|
||||||
# if request.user not in atlas.author.all():
|
# if request.user not in atlas.author.all():
|
||||||
# raise PermissionDenied
|
# raise PermissionDenied
|
||||||
series_finding_form = SeriesFindingsForm(series_id=series.id)
|
series_finding_form = SeriesFindingForm(series_id=series.id)
|
||||||
|
|
||||||
|
|
||||||
# logging.debug(atlas.subspecialty.first().name.all())
|
# logging.debug(atlas.subspecialty.first().name.all())
|
||||||
return render(request, "atlas/series.html", {"series": series, "series_finding_form": series_finding_form})
|
return render(
|
||||||
|
request,
|
||||||
|
"atlas/series.html",
|
||||||
|
{"series": series, "series_finding_form": series_finding_form},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@@ -516,28 +519,28 @@ class SeriesImagesZipView(SuperuserRequiredMixin, BaseZipView):
|
|||||||
|
|
||||||
return [i.image.file for i in series.images.all()]
|
return [i.image.file for i in series.images.all()]
|
||||||
|
|
||||||
|
|
||||||
def create_series_findings(request):
|
def create_series_findings(request):
|
||||||
#posts = Post.objects.all()
|
# posts = Post.objects.all()
|
||||||
response_data = {}
|
response_data = {}
|
||||||
|
|
||||||
if request.POST.get('action') == 'post':
|
if request.POST.get("action") == "post":
|
||||||
series_id = request.POST.get('series')
|
series_id = request.POST.get("series")
|
||||||
findings_ids = json.loads(request.POST.get('findings'))
|
findings_ids = json.loads(request.POST.get("findings"))
|
||||||
description = request.POST.get('description')
|
description = request.POST.get("description")
|
||||||
annotation_json = json.loads(request.POST.get('annotation_json'))
|
annotation_json = json.loads(request.POST.get("annotation_json"))
|
||||||
|
|
||||||
series = Series.objects.get(pk=series_id)
|
series = Series.objects.get(pk=series_id)
|
||||||
findings = Finding.objects.filter(pk__in=findings_ids)
|
findings = Finding.objects.filter(pk__in=findings_ids)
|
||||||
|
|
||||||
|
sf = SeriesFinding.objects.create(
|
||||||
sf = SeriesFindings.objects.create(
|
series=series,
|
||||||
series = series,
|
description=description,
|
||||||
description = description,
|
annotation_json=annotation_json,
|
||||||
annotation_json = annotation_json,
|
|
||||||
)
|
)
|
||||||
sf.findings.set(findings)
|
sf.findings.set(findings)
|
||||||
sf.save()
|
sf.save()
|
||||||
return JsonResponse({"success":True})
|
return JsonResponse({"success": True})
|
||||||
|
|
||||||
return JsonResponse({"success": False})
|
return JsonResponse({"success": False})
|
||||||
return render(request, 'create_post.html', {'posts':posts})
|
return render(request, "create_post.html", {"posts": posts})
|
||||||
|
|||||||
Reference in New Issue
Block a user