diff --git a/helpers/ocr.py b/helpers/ocr.py
index 622334e1..3c6d6712 100644
--- a/helpers/ocr.py
+++ b/helpers/ocr.py
@@ -6,6 +6,9 @@ import cv2
import os
import glob
+from pathlib import Path
+
+
def ocr_file(filename):
# load the example image and convert it to grayscale
image = cv2.imread(filename)
@@ -95,6 +98,8 @@ def search_image(file_name):
edit_path = "{}/test/".format(path)
+ Path(edit_path).mkdir(parents=True, exist_ok=True)
+
print(edit_path)
fn1, fn2 = fn.rsplit(".", 1)
cv2.imwrite("{}{}_new.{}".format(edit_path, fn1, fn2), img)
@@ -126,7 +131,7 @@ image_list = []
file_types = ("gif", "jpg", "jpeg", "png")
for file_type in file_types:
- for filename in glob.glob('/Users/ross/media/test/*.{}'.format(file_type)): #assuming gif
+ for filename in glob.glob('/home/ross/scripts/sites/backups/New/media/rapids/*.{}'.format(file_type)): #assuming gif
image_list.append(filename)
for f in image_list:
diff --git a/longs/admin.py b/longs/admin.py
index 71d6f1e9..a1513f43 100755
--- a/longs/admin.py
+++ b/longs/admin.py
@@ -1,5 +1,5 @@
from django.contrib import admin
-from .models import Long, LongImage, Examination, Site, Abnormality, Region, Note, LongCreationDefault, Answer, Exam
+from .models import Long, LongSeries, LongSeriesImage, Examination, Site, Note, LongCreationDefault, Exam
import tagulous.admin
@@ -12,23 +12,18 @@ from django.forms.widgets import RadioSelect
admin.site.register(Examination)
admin.site.register(Site)
admin.site.register(Exam)
-admin.site.register(Abnormality)
-admin.site.register(Region)
admin.site.register(Note)
admin.site.register(LongCreationDefault)
-admin.site.register(Answer)
-
-class LongAnswersInline(admin.TabularInline):
- model = Answer
- extra = 1
+admin.site.register(LongSeries)
+admin.site.register(LongSeriesImage)
class LongImageInline(admin.TabularInline):
- model = LongImage
+ model = LongSeries
extra = 1
- readonly_fields = [
- "image_tag",
- ]
+# readonly_fields = [
+# "image_tag",
+# ]
class ExamInline(admin.TabularInline):
model = Long.exams.through
@@ -40,30 +35,19 @@ class LongAdminForm(ModelForm):
model = Long
fields = [
- "normal", "abnormality", "region", "laterality", "examination",
- "site", "sign", "condition", "feedback", "author"
+ "site", "sign", "feedback", "author"
]
- widgets = {
- "laterality": RadioSelect(attrs={'style': 'display: inline-flex'}),
- }
-
class LongAdmin(VersionAdmin):
form = LongAdminForm
- filter_horizontal = (
- "abnormality",
- "region",
- #"examination",
- )
save_on_top = True
save_as = True
view_on_site = True
inlines = [
LongImageInline,
- LongAnswersInline,
ExamInline,
]
diff --git a/longs/filters.py b/longs/filters.py
index f1817a4b..836e1b51 100755
--- a/longs/filters.py
+++ b/longs/filters.py
@@ -6,5 +6,4 @@ from .models import Long
class LongFilter(django_filters.FilterSet):
class Meta:
model = Long
- fields = ("normal", "abnormality", "region", "examination",
- "laterality", "site", "created_date", "author")
+ fields = ("site", "created_date", "author")
diff --git a/longs/forms.py b/longs/forms.py
index 8e042186..abbc7d2c 100755
--- a/longs/forms.py
+++ b/longs/forms.py
@@ -9,14 +9,12 @@ from django.forms import (
from django.forms import inlineformset_factory
from longs.models import (
- Abnormality,
Examination,
Note,
Long,
+ LongSeries,
+ LongSeriesImage,
LongCreationDefault,
- LongImage,
- Region,
- Answer,
CidUserAnswer,
Exam,
)
@@ -28,7 +26,7 @@ from django.forms.widgets import RadioSelect, TextInput, Textarea
class LongAnswerForm(ModelForm):
class Meta:
model = CidUserAnswer
- fields = ("answer",)
+ fields = ("answer_observations","answer_interpretation","answer_principle_diagnosis","answer_differential_diagnosis","answer_further_management",)
class MarkLongQuestionForm(Form):
@@ -50,17 +48,6 @@ class NoteForm(ModelForm):
fields = ["note"]
-class RegionForm(ModelForm):
- class Meta:
- model = Region
- fields = ["name"]
-
-
-class AbnormalityForm(ModelForm):
- class Meta:
- model = Abnormality
- fields = ["name"]
-
class LongCreationDefaultForm(ModelForm):
class Meta:
@@ -85,37 +72,17 @@ class LongForm(ModelForm):
super(LongForm, self).__init__(*args, **kwargs)
# self.fields['question'].widget.attrs = {'class': 'question-form', 'rows': 10, 'cols': 100}
# self.fields['feedback'].widget.attrs = {'class': 'feedback-form', 'rows': 10, 'cols': 100}
- self.fields["abnormality"] = ModelMultipleChoiceField(
- required=False,
- queryset=Abnormality.objects.all(),
- widget=FilteredSelectMultiple(verbose_name="Abnormality", is_stacked=False),
- )
-
- self.fields["region"] = ModelMultipleChoiceField(
- required=False,
- queryset=Region.objects.all(),
- widget=FilteredSelectMultiple(verbose_name="Region", is_stacked=False),
- )
-
- self.fields["examination"] = ModelMultipleChoiceField(
- queryset=Examination.objects.all(),
- widget=FilteredSelectMultiple(verbose_name="Examination", is_stacked=False),
- )
-
- self.fields["laterality"] = ChoiceField(
- choices=Long.LATERALITY_CHOICES, required=True, widget=RadioSelect()
- )
+ #self.fields["examination"] = ModelMultipleChoiceField(
+ # queryset=Examination.objects.all(),
+ # widget=FilteredSelectMultiple(verbose_name="Examination", is_stacked=False),
+ #)
class Meta:
model = Long
# fields = ['due_back']
# fields = '__all__'
fields = [
- "normal",
- "abnormality",
- "region",
- "laterality",
- "examination",
+ #"examination",
"site",
"feedback",
]
@@ -127,43 +94,12 @@ class LongForm(ModelForm):
}
-ImageFormSet = inlineformset_factory(
+SeriesFormSet = inlineformset_factory(
Long,
- LongImage,
- fields=["image", "feedback_image"],
+ LongSeries,
exclude=[],
can_delete=True,
extra=4,
max_num=10,
field_classes="testing",
)
-
-AnswerFormSet = inlineformset_factory(
- Long,
- Answer,
- fields=["answer", "status"],
- widgets={
- "answer": Textarea(
- attrs={"required": "true", "minlength": 2, "maxlength": 500, "rows": 3}
- )
- },
- exclude=[],
- can_delete=True,
- extra=1,
- max_num=10,
-)
-
-AnswerUpdateFormSet = inlineformset_factory(
- Long,
- Answer,
- fields=["answer", "status"],
- widgets={
- "answer": Textarea(
- attrs={"required": "true", "minlength": 2, "maxlength": 500, "rows": 3}
- )
- },
- exclude=[],
- can_delete=True,
- extra=0,
- max_num=10,
-)
\ No newline at end of file
diff --git a/longs/migrations/0001_initial.py b/longs/migrations/0001_initial.py
new file mode 100644
index 00000000..ab3c34a7
--- /dev/null
+++ b/longs/migrations/0001_initial.py
@@ -0,0 +1,155 @@
+# Generated by Django 3.1.3 on 2021-02-02 19:46
+
+from django.conf import settings
+import django.core.files.storage
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+import longs.models
+import sortedm2m.fields
+import tagulous.models.models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('anatomy', '0024_auto_20210130_1515'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Examination',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('examination', models.CharField(max_length=200)),
+ ],
+ options={
+ 'ordering': ('examination',),
+ },
+ ),
+ migrations.CreateModel(
+ name='Long',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('question', models.TextField(blank=True, null=True)),
+ ('feedback', models.TextField(blank=True, null=True)),
+ ('sign', models.CharField(blank=True, max_length=255)),
+ ('verified', models.BooleanField(default=False)),
+ ('created_date', models.DateTimeField(default=django.utils.timezone.now)),
+ ('published_date', models.DateTimeField(blank=True, null=True)),
+ ('scrapped', models.BooleanField(default=False, help_text='Question has been scrapped and will not be shown')),
+ ('open_access', models.BooleanField(default=True, help_text='If an question should be freely available to browse')),
+ ('author', models.ManyToManyField(blank=True, help_text='Author of question', related_name='long_authored_questions', to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='LongSeries',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('examination', models.ForeignKey(help_text='Name of the examination', null=True, on_delete=django.db.models.deletion.SET_NULL, to='longs.examination')),
+ ('long', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='long', to='longs.long')),
+ ('modality', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='series_modality', to='anatomy.modality')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Site',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('site', models.CharField(max_length=200)),
+ ('initials', models.CharField(max_length=200)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Sign',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=255, unique=True)),
+ ('slug', models.SlugField()),
+ ('count', models.IntegerField(default=0, help_text='Internal counter of how many times this tag is in use')),
+ ('protected', models.BooleanField(default=False, help_text='Will not be deleted when the count reaches 0')),
+ ],
+ options={
+ 'ordering': ('name',),
+ 'abstract': False,
+ 'unique_together': {('slug',)},
+ },
+ bases=(tagulous.models.models.BaseTagModel, models.Model),
+ ),
+ migrations.CreateModel(
+ name='Note',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('note', models.TextField()),
+ ('created_on', models.DateTimeField(auto_now_add=True)),
+ ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='long_notes', to=settings.AUTH_USER_MODEL)),
+ ('long', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='long_notes', to='longs.long')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='LongSeriesImage',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('image', models.ImageField(storage=django.core.files.storage.FileSystemStorage(base_url='/media/longs/', location='/home/ross/scripts/sites/rad/media//longs/'), upload_to=longs.models.image_directory_path)),
+ ('position', models.IntegerField(default=0)),
+ ('series', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='series', to='longs.longseries')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='LongCreationDefault',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('author', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='long_default', to=settings.AUTH_USER_MODEL)),
+ ('site', models.ManyToManyField(blank=True, default=1, help_text='Default site to use when creating a new long', to='longs.Site')),
+ ],
+ ),
+ migrations.AddField(
+ model_name='long',
+ name='site',
+ field=models.ManyToManyField(blank=True, default=1, help_text='If we know the source of the image', to='longs.Site'),
+ ),
+ migrations.CreateModel(
+ name='Exam',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=200)),
+ ('active', models.BooleanField(default=True, help_text='If an exam should be available')),
+ ('publish_results', models.BooleanField(default=True, help_text='If an exams results should be available')),
+ ('recreate_json', models.BooleanField(default=False, help_text='If the json cache needs updating')),
+ ('time_limit', models.IntegerField(default=2100, help_text='Exam time limit (in seconds). Default is 2100 secondse (35 minutes)')),
+ ('exam_questions', sortedm2m.fields.SortedManyToManyField(blank='true', help_text=None, related_name='exams', to='longs.Long')),
+ ],
+ ),
+ migrations.CreateModel(
+ name='Condition',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=255, unique=True)),
+ ('slug', models.SlugField()),
+ ('count', models.IntegerField(default=0, help_text='Internal counter of how many times this tag is in use')),
+ ('protected', models.BooleanField(default=False, help_text='Will not be deleted when the count reaches 0')),
+ ],
+ options={
+ 'ordering': ('name',),
+ 'abstract': False,
+ 'unique_together': {('slug',)},
+ },
+ bases=(tagulous.models.models.BaseTagModel, models.Model),
+ ),
+ migrations.CreateModel(
+ name='CidUserAnswer',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('normal', models.BooleanField(default=False)),
+ ('answer', models.TextField(blank=True, max_length=500)),
+ ('answer_compare', models.TextField(blank=True, max_length=500)),
+ ('cid', models.BigIntegerField(blank=True, help_text='Candidate ID (limitied by BigIntegerField size)', null=True)),
+ ('created', models.DateTimeField(auto_now_add=True)),
+ ('updated', models.DateTimeField(auto_now=True)),
+ ('exam', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cid_user_answers', to='longs.exam')),
+ ('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cid_user_answers', to='longs.long')),
+ ],
+ ),
+ ]
diff --git a/longs/migrations/__init__.py b/longs/migrations/__init__.py
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/longs/migrations/__init__.py
@@ -0,0 +1 @@
+
diff --git a/longs/models.py b/longs/models.py
index fd839611..d9735469 100644
--- a/longs/models.py
+++ b/longs/models.py
@@ -1,3 +1,6 @@
+from django.db.models.fields.files import ImageField
+from django.db.models.fields.related import ForeignKey
+from anatomy.models import Modality
from django.db import models
from django.utils import timezone
import tagulous
@@ -29,32 +32,6 @@ def image_directory_path(instance, filename):
-class Abnormality(models.Model):
- name = models.CharField(max_length=200,
- unique=True,
- help_text="Primary abnormality on the film(s)")
-
- def __str__(self):
- return self.name
-
- class Meta:
- ordering = ('name', )
-
-
-class Region(models.Model):
- name = models.CharField(
- max_length=200,
- unique=True,
- help_text="Region of the abnormality (not including lateralitiy)",
- blank=True)
-
- def __str__(self):
- return self.name
-
- class Meta:
- ordering = ('name', )
-
-
class Examination(models.Model):
examination = models.CharField(max_length=200)
@@ -79,39 +56,6 @@ class Condition(tagulous.models.TagModel):
class Sign(tagulous.models.TagModel):
pass
-class Answer(models.Model):
- question = models.ForeignKey(
- "Long", related_name="answers", on_delete=models.CASCADE
- )
- answer = models.TextField(max_length=500)
- answer_compare = models.TextField(max_length=500)
-
- class MarkOptions(models.TextChoices):
- UNMARKED = "", _("Unmarked")
- INCORRECT = "0", _("Incorrect")
- HALF_MARK = "1", _("Half mark")
- CORRECT = "2", _("Correct")
-
- status = models.CharField(
- max_length=1, choices=MarkOptions.choices, default=MarkOptions.UNMARKED
- )
-
- def __str__(self):
- return self.answer
-
- def save(self, *args, **kwargs):
- self.clean()
- return super(Answer, self).save(*args, **kwargs)
-
- def clean(self):
- if self.answer:
- self.answer = self.answer.strip()
-
- s = self.answer.lower()
- s = s.translate(str.maketrans('', '', string.punctuation))
-
- self.answer_compare = s
-
class Long(models.Model):
#author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
@@ -119,37 +63,6 @@ class Long(models.Model):
question = models.TextField(null=True, blank=True)
feedback = models.TextField(null=True, blank=True)
- normal = models.BooleanField(default=False, help_text="Tick if true")
-
- NONE = "NONE"
- LEFT = "LEFT"
- RIGHT = "RIGHT"
- BILATERAL = "BILAT"
-
- LATERALITY_CHOICES = (
- (NONE, "None"),
- (LEFT, "Left"),
- (RIGHT, "Right"),
- (BILATERAL, "Bilateral"),
- )
-
- abnormality = models.ManyToManyField(
- Abnormality,
- blank=True,
- help_text="The abnormality (laterality and region independent). Used for categorisation but does not affect the answer",
- )
- region = models.ManyToManyField(
- Region,
- blank=True,
- help_text="Region of the abnormality (laterality independent)")
- examination = models.ManyToManyField(
- Examination, help_text="Name of the (primary) examination")
- laterality = models.CharField(
- max_length=20,
- choices=LATERALITY_CHOICES,
- default=NONE,
- help_text="Applies to the answer, not the examination")
- condition = models.CharField(max_length=255, blank=True)
#condition = tagulous.models.TagField(
# to=Condition,
# blank=True,
@@ -161,6 +74,14 @@ class Long(models.Model):
#sign = tagulous.models.TagField(
# to=Sign, blank=True, help_text='Radiological signs in the question')
+ # Model answers
+ model_observations = models.TextField(null=True, blank=True)
+ model_interpretation = models.TextField(null=True, blank=True)
+ model_principle_diagnosis = models.TextField(null=True, blank=True)
+ model_differential_diagnosis = models.TextField(null=True, blank=True)
+ model_further_management = models.TextField(null=True, blank=True)
+
+
DEFAULT_SITE_ID = 1
site = models.ManyToManyField(
Site,
@@ -193,91 +114,23 @@ class Long(models.Model):
authors = ", ".join([i.username for i in self.author.all()])
return authors
- def get_regions(self):
- """Returns a comma seperated text list of regions"""
- regions = ", ".join([i.name for i in self.region.all()])
- return regions
-
- def get_abnormalities(self):
- """Returns a comma seperated text list of regions"""
- abnormalities = ", ".join([i.name for i in self.abnormality.all()])
- return abnormalities
-
def get_examinations(self):
"""Returns a comma seperated text list of regions"""
examinations = ", ".join([i.examination for i in self.examination.all()])
return examinations
def __str__(self):
- n = "Normal"
- if not self.normal:
- #n = self.answers.first()
- n = "{} / {}".format(self.abnormality.first(), self.region.first())
exams = self.get_examinations()
lat = ""
if self.laterality != "NONE":
lat = self.laterality
return "{} / {} {}".format(exams, lat, n)
- def GetPrimaryAnswer(self):
- if len(self.answers.all()) > 0:
- return self.answers.all().first().answer
- elif self.normal:
- return "Normal"
- else:
- return "None yet..."
-
def GetExams(self):
e = self.exams.all().values_list("name", flat=True)
exams = ", ".join(e)
return exams
- def GetUnmarkedAnswersString(self):
- unmarked_answers = self.GetUnmarkedAnswers()
-
- if not unmarked_answers:
- return "No answers to mark"
- return format_html(
- "{} answer unmarked: {}".format(
- len(unmarked_answers), ", ".join(unmarked_answers)
- )
- )
-
- def GetUnmarkedAnswers(self):
- # If normal no answers to mark
- if self.normal:
- return []
-
- user_answers = set(
- [i.answer_compare for i in self.cid_user_answers.all() if i.normal == False]
- )
- unmarked_answers = user_answers - self.GetMarkedAnswers()
-
- return unmarked_answers
-
- def GetUnmarkedAnswerCount(self):
- return len(self.GetUnmarkedAnswers())
-
- def GetMarkedAnswers(self):
- return set(
- [
- i.answer_compare
- for i in self.answers.all()
- if i.status != i.MarkOptions.UNMARKED
- ]
- )
- correct_answers = set(
- [i.answer.get_compare_string() for i in self.answers.all()]
- )
- half_mark_answers = set(
- [i.answer.get_compare_string() for i in self.half_mark_answers.all()]
- )
- incorrect_answers = set(
- [i.answer.get_compare_string() for i in self.incorrect_answers.all()]
- )
-
- marked_answers = correct_answers | half_mark_answers | incorrect_answers
- return marked_answers
def GetImages(self, feedback=False):
qs = self.images.all()
@@ -294,24 +147,34 @@ class Long(models.Model):
#def GetNonFeedbackQuestionImages(self):
#return self.GetImages()
-
-class LongImage(models.Model):
- long = models.ForeignKey(Long,
- related_name="images",
- on_delete=models.CASCADE)
+class LongSeriesImage(models.Model):
image = models.ImageField(upload_to=image_directory_path, storage=image_storage)
+ position = models.IntegerField(default=0)
+ series = models.ForeignKey("LongSeries", related_name="series", on_delete=models.SET_NULL, null=True)
- feedback_image = models.BooleanField(default=False)
+class LongSeries(models.Model):
+ modality = models.ForeignKey(Modality, related_name="series_modality", on_delete=models.SET_NULL, null=True)
+ examination = models.ForeignKey(
+ Examination, help_text="Name of the examination", on_delete=models.SET_NULL, null=True)
+ long = models.ForeignKey("Long", related_name="long", on_delete=models.SET_NULL, null=True)
- def image_tag(self):
- if self.image:
- return mark_safe(
- '
Click and hold to zoom'
- .format(self.image.url))
- else:
- return ""
-
- image_tag.short_description = 'Image'
+#class LongImage(models.Model):
+# long = models.ForeignKey(Long,
+# related_name="images",
+# on_delete=models.CASCADE)
+# image = models.ImageField(upload_to=image_directory_path, storage=image_storage)
+#
+# feedback_image = models.BooleanField(default=False)
+#
+# def image_tag(self):
+# if self.image:
+# return mark_safe(
+# '
Click and hold to zoom'
+# .format(self.image.url))
+# else:
+# return ""
+#
+# image_tag.short_description = 'Image'
class Note(models.Model):
@@ -395,11 +258,14 @@ class CidUserAnswer(models.Model):
Long, related_name="cid_user_answers", on_delete=models.CASCADE
)
- # For longs the answer can be normal in which case the below field is true
- normal = models.BooleanField(default=False)
- answer = models.TextField(max_length=500, blank=True)
- answer_compare = models.TextField(max_length=500, blank=True)
+ # Answers
+ answer_observations = models.TextField(null=True, blank=True)
+ answer_interpretation = models.TextField(null=True, blank=True)
+ answer_principle_diagnosis = models.TextField(null=True, blank=True)
+ answer_differential_diagnosis = models.TextField(null=True, blank=True)
+ answer_further_management = models.TextField(null=True, blank=True)
+
cid = models.BigIntegerField(blank=True, null=True, help_text="Candidate ID (limitied by BigIntegerField size)")
diff --git a/longs/templates/rapids/author_list.html b/longs/templates/longs/author_list.html
similarity index 100%
rename from longs/templates/rapids/author_list.html
rename to longs/templates/longs/author_list.html
diff --git a/longs/templates/rapids/base.html b/longs/templates/longs/base.html
similarity index 100%
rename from longs/templates/rapids/base.html
rename to longs/templates/longs/base.html
diff --git a/longs/templates/rapids/category_detail.html b/longs/templates/longs/category_detail.html
similarity index 100%
rename from longs/templates/rapids/category_detail.html
rename to longs/templates/longs/category_detail.html
diff --git a/longs/templates/rapids/create_simple.html b/longs/templates/longs/create_simple.html
similarity index 100%
rename from longs/templates/rapids/create_simple.html
rename to longs/templates/longs/create_simple.html
diff --git a/longs/templates/rapids/exam.html b/longs/templates/longs/exam.html
similarity index 100%
rename from longs/templates/rapids/exam.html
rename to longs/templates/longs/exam.html
diff --git a/longs/templates/rapids/exam_list.html b/longs/templates/longs/exam_list.html
similarity index 100%
rename from longs/templates/rapids/exam_list.html
rename to longs/templates/longs/exam_list.html
diff --git a/longs/templates/rapids/exam_overview.html b/longs/templates/longs/exam_overview.html
similarity index 100%
rename from longs/templates/rapids/exam_overview.html
rename to longs/templates/longs/exam_overview.html
diff --git a/longs/templates/rapids/exam_scores.html b/longs/templates/longs/exam_scores.html
similarity index 100%
rename from longs/templates/rapids/exam_scores.html
rename to longs/templates/longs/exam_scores.html
diff --git a/longs/templates/rapids/exam_scores_user.html b/longs/templates/longs/exam_scores_user.html
similarity index 100%
rename from longs/templates/rapids/exam_scores_user.html
rename to longs/templates/longs/exam_scores_user.html
diff --git a/longs/templates/rapids/exams.html b/longs/templates/longs/exams.html
similarity index 100%
rename from longs/templates/rapids/exams.html
rename to longs/templates/longs/exams.html
diff --git a/longs/templates/rapids/index.html b/longs/templates/longs/index.html
similarity index 100%
rename from longs/templates/rapids/index.html
rename to longs/templates/longs/index.html
diff --git a/longs/templates/rapids/index_old.html b/longs/templates/longs/index_old.html
similarity index 100%
rename from longs/templates/rapids/index_old.html
rename to longs/templates/longs/index_old.html
diff --git a/longs/templates/rapids/mark.html b/longs/templates/longs/mark.html
similarity index 100%
rename from longs/templates/rapids/mark.html
rename to longs/templates/longs/mark.html
diff --git a/longs/templates/rapids/mark_overview.html b/longs/templates/longs/mark_overview.html
similarity index 100%
rename from longs/templates/rapids/mark_overview.html
rename to longs/templates/longs/mark_overview.html
diff --git a/longs/templates/rapids/note_form.html b/longs/templates/longs/note_form.html
similarity index 100%
rename from longs/templates/rapids/note_form.html
rename to longs/templates/longs/note_form.html
diff --git a/longs/templates/rapids/rapid_detail.html b/longs/templates/longs/rapid_detail.html
similarity index 100%
rename from longs/templates/rapids/rapid_detail.html
rename to longs/templates/longs/rapid_detail.html
diff --git a/longs/templates/rapids/rapid_display_block.html b/longs/templates/longs/rapid_display_block.html
similarity index 100%
rename from longs/templates/rapids/rapid_display_block.html
rename to longs/templates/longs/rapid_display_block.html
diff --git a/longs/templates/rapids/rapid_form.html b/longs/templates/longs/rapid_form.html
similarity index 100%
rename from longs/templates/rapids/rapid_form.html
rename to longs/templates/longs/rapid_form.html
diff --git a/longs/templates/rapids/rapidcreationdefault_form.html b/longs/templates/longs/rapidcreationdefault_form.html
similarity index 100%
rename from longs/templates/rapids/rapidcreationdefault_form.html
rename to longs/templates/longs/rapidcreationdefault_form.html
diff --git a/longs/templates/rapids/view.html b/longs/templates/longs/view.html
similarity index 100%
rename from longs/templates/rapids/view.html
rename to longs/templates/longs/view.html
diff --git a/longs/views.py b/longs/views.py
index 12b29166..267e598c 100755
--- a/longs/views.py
+++ b/longs/views.py
@@ -21,22 +21,15 @@ from django.http import HttpResponseRedirect, HttpResponse
from .forms import (
LongForm,
MarkLongQuestionForm,
- ImageFormSet,
+ SeriesFormSet,
NoteForm,
- RegionForm,
- AbnormalityForm,
ExaminationForm,
- AnswerFormSet,
- AnswerUpdateFormSet,
)
from .models import (
Long,
Note,
- Abnormality,
- Region,
Examination,
Exam,
- Answer,
CidUserAnswer,
)
from .tables import LongTable
@@ -236,28 +229,24 @@ def long_clone(request, pk):
form = LongForm(request.POST or None, instance=new_item)
- image_formset = ImageFormSet()
- answer_formset = AnswerFormSet()
+ series_formset = SeriesFormSet()
if form.is_valid():
form.instance.author.add(request.user.id)
# logger.debug(formset.is_valid())
- if image_formset.is_valid() and answer_formset.is_valid():
+ if series_formset.is_valid():
response = super().form_valid(form)
- image_formset.instance = obj
- image_formset.save()
+ series_formset.instance = obj
+ series_formset.save()
- answer_formset.instance = obj
- answer_formset.save()
return response
else:
return super().form_invalid(form)
context = {
"form": form,
- "image_formset": image_formset,
- "answer_formset": answer_formset
+ "series_formset": series_formset,
# other context
}
@@ -271,15 +260,12 @@ class LongCreateBase(LoginRequiredMixin, CreateView):
def get_context_data(self, **kwargs):
context = super(LongCreateBase, self).get_context_data(**kwargs)
if self.request.POST:
- context["image_formset"] = ImageFormSet(
+ context["series_formset"] = SeriesFormSet(
self.request.POST, self.request.FILES
)
- context["image_formset"].full_clean()
- context["answer_formset"] = AnswerFormSet(self.request.POST)
- context["answer_formset"].full_clean()
+ context["series_formset"].full_clean()
else:
- context["image_formset"] = ImageFormSet()
- context["answer_formset"] = AnswerFormSet()
+ context["series_formset"] = SeriesFormSet()
return context
def form_valid(self, form):
@@ -290,14 +276,11 @@ class LongCreateBase(LoginRequiredMixin, CreateView):
form.instance.author.add(self.request.user.id)
context = self.get_context_data(form=form)
- image_formset = context["image_formset"]
- answer_formset = context["answer_formset"]
- if image_formset.is_valid() and answer_formset.is_valid():
+ series_formset = context["series_formset"]
+ if series_formset.is_valid():
response = super().form_valid(form)
- image_formset.instance = self.object
- image_formset.save()
- answer_formset.instance = self.object
- answer_formset.save()
+ series_formset.instance = self.object
+ series_formset.save()
# If the normal submit button is pressed we save as normal
if "submit" in self.request.POST:
return response
@@ -312,7 +295,6 @@ class LongCreateBase(LoginRequiredMixin, CreateView):
# @login_required
class LongCreate(LongCreateBase):
- initial = {"laterality": Long.NONE}
def get_initial(self):
# There has to be a better way...
@@ -346,17 +328,12 @@ class LongUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView):
def get_context_data(self, **kwargs):
context = super(LongUpdate, self).get_context_data(**kwargs)
if self.request.POST:
- context["image_formset"] = ImageFormSet(
+ context["series_formset"] = SeriesFormSet(
self.request.POST, self.request.FILES, instance=self.object
)
- context["image_formset"].full_clean()
- context["answer_formset"] = AnswerFormSet(
- self.request.POST, instance=self.object
- )
- context["answer_formset"].full_clean()
+ context["series_formset"].full_clean()
else:
- context["image_formset"] = ImageFormSet(instance=self.object)
- context["answer_formset"] = AnswerFormSet(instance=self.object)
+ context["series_formset"] = SeriesFormSet(instance=self.object)
return context
def form_valid(self, form):
@@ -367,15 +344,12 @@ class LongUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView):
form.instance.author.add(self.request.user.id)
context = self.get_context_data(form=form)
- image_formset = context["image_formset"]
- answer_formset = context["answer_formset"]
+ series_formset = context["series_formset"]
# logger.debug(formset.is_valid())
- if image_formset.is_valid() and answer_formset.is_valid():
+ if series_formset.is_valid():
response = super().form_valid(form)
- image_formset.instance = self.object
- image_formset.save()
- answer_formset.instance = self.object
- answer_formset.save()
+ series_formset.instance = self.object
+ series_formset.save()
return response
else:
return super().form_invalid(form)
diff --git a/rad/settings.py b/rad/settings.py
index 0d4cb924..5140d53c 100644
--- a/rad/settings.py
+++ b/rad/settings.py
@@ -33,6 +33,7 @@ INSTALLED_APPS = [
'anatomy',
'physics',
'rapids',
+ 'longs',
"reversion",
"django_tables2",
"django_filters",
diff --git a/rad/urls.py b/rad/urls.py
index 4955b893..e698a074 100644
--- a/rad/urls.py
+++ b/rad/urls.py
@@ -28,6 +28,7 @@ urlpatterns = [
path("physics/", include("physics.urls"), name="physics"),
#path("sbas/", include("sbas.urls"), name="sbas"),
path("rapids/", include("rapids.urls"), name="rapids"),
+ path("longs/", include("longs.urls"), name="longs"),
path("accounts/", include("django.contrib.auth.urls")),
path("accounts/profile", views.profile, name="profile"),
path("", TemplateView.as_view(template_name="index.html"), name="home"),
diff --git a/rapids/models.py b/rapids/models.py
index 83fbb41b..c9d462ef 100644
--- a/rapids/models.py
+++ b/rapids/models.py
@@ -25,6 +25,7 @@ image_storage = FileSystemStorage(
)
def image_directory_path(instance, filename):
+ return u"{0}".format(filename)
return u"picture/{0}".format(filename)
diff --git a/temp.png b/temp.png
new file mode 100644
index 00000000..d71aeac4
Binary files /dev/null and b/temp.png differ