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