more improvements

This commit is contained in:
Ross
2021-02-04 10:30:56 +00:00
parent b681a27640
commit cd013f2ff3
32 changed files with 247 additions and 324 deletions
+6 -1
View File
@@ -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:
+8 -24
View File
@@ -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,
]
+1 -2
View File
@@ -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")
+10 -74
View File
@@ -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,
)
+155
View File
@@ -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')),
],
),
]
+1
View File
@@ -0,0 +1 @@
+43 -177
View File
@@ -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(
"<span class='warn'>{} answer unmarked:</span> {}".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(
'<img src="{}" class="admin-long-image" /><span class="admin-long-image-info">Click and hold to zoom<span>'
.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(
# '<img src="{}" class="admin-long-image" /><span class="admin-long-image-info">Click and hold to zoom<span>'
# .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)")
+20 -46
View File
@@ -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)
+1
View File
@@ -33,6 +33,7 @@ INSTALLED_APPS = [
'anatomy',
'physics',
'rapids',
'longs',
"reversion",
"django_tables2",
"django_filters",
+1
View File
@@ -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"),
+1
View File
@@ -25,6 +25,7 @@ image_storage = FileSystemStorage(
)
def image_directory_path(instance, filename):
return u"{0}".format(filename)
return u"picture/{0}".format(filename)
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 446 B