From bf719e61cb138efd0d850190989f0db1b20531a2 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 29 Nov 2021 22:57:51 +0000 Subject: [PATCH] . --- atlas/forms.py | 12 +++++++++++- atlas/models.py | 22 ++++++++++++++++------ atlas/templates/atlas/case_form.html | 2 +- atlas/views.py | 27 ++++++++++++++++++++++++--- sbas/urls.py | 7 +++++++ 5 files changed, 59 insertions(+), 11 deletions(-) diff --git a/atlas/forms.py b/atlas/forms.py index d0d13c5d..01e50c99 100755 --- a/atlas/forms.py +++ b/atlas/forms.py @@ -8,7 +8,7 @@ from django.forms import ( ) from django.forms import inlineformset_factory -from atlas.models import Case, Series, SeriesImage, SeriesFinding +from atlas.models import Case, Differential, Series, SeriesImage, SeriesFinding from anatomy.models import Modality @@ -21,6 +21,7 @@ from django.forms.widgets import RadioSelect, TextInput, Textarea from tinymce.widgets import TinyMCE +from dal import autocomplete class ExaminationForm(ModelForm): class Meta: @@ -173,6 +174,7 @@ class CaseForm(ModelForm): # "mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}), "description": Textarea(attrs={"cols": 80, "rows": 5}), "history": Textarea(attrs={"cols": 80, "rows": 5}), + "condition" : autocomplete.ModelSelect2(url='atlas:condition-autocomplete') } def save(self, commit=True): @@ -198,6 +200,14 @@ class CaseForm(ModelForm): return instance +CaseDifferentialFormSet = inlineformset_factory( + Case, + Differential, + exclude=[], + can_delete=True, + extra=0, + max_num=10, +) SeriesFormSet = inlineformset_factory( Case, diff --git a/atlas/models.py b/atlas/models.py index 98d33e43..2678c3e0 100644 --- a/atlas/models.py +++ b/atlas/models.py @@ -90,14 +90,14 @@ class SynMixin(object): class Finding(SynMixin, models.Model): - name = models.CharField(max_length=255) + name = models.CharField(max_length=255, unique=True) synonym = models.ManyToManyField("self", blank=True) primary_name = models.BooleanField(default="True") class Condition(SynMixin, models.Model): - name = models.CharField(max_length=255) + name = models.CharField(max_length=255, unique=True) synonym = models.ManyToManyField("self", blank=True) @@ -114,15 +114,22 @@ class Subspecialty(models.Model): class Differential(models.Model): - condition = models.ForeignKey( - Condition, on_delete=models.CASCADE - ) + condition = models.ForeignKey(Condition, on_delete=models.CASCADE) case = models.ForeignKey( "Case", on_delete=models.CASCADE, related_name="differentialcase" ) text = models.TextField(null=True, blank=True) +class Structure(SynMixin, models.Model): + structure = models.CharField(max_length=255, unique=True) + + synonym = models.ManyToManyField("self", blank=True) + + primary_name = models.BooleanField(default="True") + + + @reversion.register class Case(models.Model): # class SubspecialtyChoices(models.TextChoices): @@ -156,7 +163,9 @@ class Case(models.Model): condition = models.ManyToManyField(Condition, blank=True) - differential = models.ManyToManyField(Condition, through=Differential, related_name="casedifferential") + differential = models.ManyToManyField( + Condition, through=Differential, related_name="casedifferential" + ) sign = tagulous.models.TagField( to=Sign, blank=True, help_text="Radiological signs in the question" @@ -232,6 +241,7 @@ class SeriesFinding(models.Model): null=True, blank=True, help_text="Findings on the series / stack" ) findings = models.ManyToManyField(Finding, blank=True) + structures = models.ManyToManyField(Structure, blank=True) annotation_json = models.TextField(null=True, blank=True) viewport_json = models.TextField(null=True, blank=True) diff --git a/atlas/templates/atlas/case_form.html b/atlas/templates/atlas/case_form.html index 9e382aff..a6804023 100755 --- a/atlas/templates/atlas/case_form.html +++ b/atlas/templates/atlas/case_form.html @@ -42,7 +42,7 @@ {% endblock %} {% block content %} -

Submit Long Case

+

Submit Case

Use this form to create a atlas case. Existing associated image sets can be added using this form.
{% csrf_token %} diff --git a/atlas/views.py b/atlas/views.py index 314f047d..755f4937 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -1,4 +1,5 @@ import json +from dal import autocomplete from django.shortcuts import render, get_object_or_404, redirect from django import forms @@ -6,6 +7,7 @@ from django import forms from django.contrib.auth.decorators import login_required, user_passes_test from django.contrib.auth.models import User from django.core.exceptions import ( + FieldError, ObjectDoesNotExist, PermissionDenied, ViewDoesNotExist, @@ -34,6 +36,7 @@ from .forms import ( ) from .models import ( Case, + Condition, Series, Examination, Finding, @@ -152,17 +155,17 @@ class AtlasDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView): model = Case success_url = reverse_lazy("atlas:case_view") + class SeriesFindingDelete(RevisionMixin, PermissionRequiredMixin, DeleteView): - permission_required = 'atlas.delete_seriesfinding' + permission_required = "atlas.delete_seriesfinding" model = SeriesFinding template_name = "confirm_delete.html" - #success_url = reverse_lazy("atlas:case_view") + # success_url = reverse_lazy("atlas:case_view") def get_success_url(self): pk = self.kwargs["pk"] series_id = get_object_or_404(SeriesFinding, pk=pk).series.id return reverse("atlas:series_detail", kwargs={"pk": series_id}) - class SeriesDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView): @@ -558,3 +561,21 @@ def create_series_findings(request): return JsonResponse({"success": False}) return render(request, "create_post.html", {"posts": posts}) + + +class ConditionAutocomplete(autocomplete.Select2QuerySetView): + def get_queryset(self): + # Don't forget to filter out results depending on the visitor ! + if not self.request.user.is_authenticated: + return Condition.objects.none() + + qs = Condition.objects.all() + + if self.q: + # This raises a fielderror which breaks creating a new item if not caught + try: + qs = qs.filter(name__istartswith=self.q) + except FieldError: + return Condition.objects.none() + + return qs diff --git a/sbas/urls.py b/sbas/urls.py index 36e29648..99aa22ad 100644 --- a/sbas/urls.py +++ b/sbas/urls.py @@ -1,4 +1,6 @@ from django.urls import path, include + +from atlas.models import Condition from . import views from django.views.decorators.cache import cache_page @@ -42,5 +44,10 @@ urlpatterns = [ views.GenericViews.user_answer_delete_multiple, name="user_answer_delete_multiple", ), + path( + "condition-autocomplete", + views.ConditionAutocomplete.as_view(model=Condition, create_field='structure'), + name="condition-autocomplete", + ), ]