Files
penracourses/oef/views.py
T
Ross 3b258adf59 .
2025-01-02 20:47:29 +00:00

381 lines
10 KiB
Python

from collections import defaultdict
from dataclasses import dataclass
from difflib import HtmlDiff, SequenceMatcher
from django import forms
from django.http import HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, render
from django.views.generic.edit import UpdateView, CreateView
from django.views.generic.detail import DetailView
from atlas.models import Subspecialty
from .models import Entry, Formats
# Create your views here.
from .tables import EntryTable
from .filters import EntryFilter
from django_filters.views import FilterView
from django.contrib.auth.decorators import user_passes_test
from django_tables2 import SingleTableView, SingleTableMixin
class EntryUpdateView(UpdateView):
model = Entry
template_name = "oef/entry_update_view.html"
fields = ["modality", "exam_code", "exam_name", "questions", "comments", "inactive"]
class EntryDetailView(DetailView):
model = Entry
template_name = "oef/entry_detail_view.html"
class FormatsCreateView(CreateView):
model = Formats
template_name_suffix = "_update_form"
fields = ["name", "format", "inherits"]
class FormatsForm(forms.ModelForm):
class Meta:
model = Formats
fields = ["name", "format", "specialties", "inherits"]
widgets = {"specialties": forms.CheckboxSelectMultiple()}
class FormatsUpdateView(UpdateView):
model = Formats
template_name_suffix = "_update_form"
# fields = ['name', 'format', 'specialties', 'inherits']
form_class = FormatsForm
class EntryTableView(SingleTableMixin, FilterView):
model = Entry
table_class = EntryTable
template_name = "oef/entry_table.html"
filterset_class = EntryFilter
@dataclass
class FormatOutput:
name: str
action: str = ""
field_seq: int = 100
field_label: str = ""
field_name: str = ""
field_status: str = ""
field_type: str = ""
field_codeset: str = ""
def output(request):
formats = Formats.objects.all()
formats = sorted(formats, key=lambda x: len(x.format))
outputs = []
codesets = []
codeset_start = 100000
for format in formats:
seq = 100
questions = format.format.strip().split("---")
for question in questions:
print(question)
if not question:
continue
name, *other = question.strip().splitlines()
status = "OPTIONAL"
if name.endswith("*"):
status = "REQUIRED"
name = name[:-1]
field_type = ""
match other:
case ["Yes", "No"]:
field_type = "YES/NO"
case ["Date/Time"]:
field_type = "DATE/TIME"
case ["Freetext"]:
field_type = "ALPHANUMERIC"
case [*codeset]:
field_type = "CODESET"
case _:
field_type = "unknown"
o = FormatOutput(
format.name,
field_label=name,
field_name=name,
field_seq=seq,
field_status=status,
field_type=field_type,
)
if field_type == "CODESET":
o.field_codeset = codeset_start
codesets.append((codeset_start, other))
codeset_start = codeset_start + 100
outputs.append(o)
seq = seq + 100
return render(
request,
"oef/output.html",
{"formats": formats, "outputs": outputs, "codesets": codesets},
)
def formats_view(request):
formats = Formats.objects.all()
return render(request, "oef/formats_view.html", {"formats": formats})
def formats_dupe_view(request):
formats = Formats.objects.all()
format_dict = defaultdict(list)
dupes = []
for format in formats:
if format.format in format_dict:
dupes.append((format, format_dict[format.format]))
format_dict[format.format].append(format)
return render(request, "oef/formats_dupe_view.html", {"dupes": dupes, "format_dict": format_dict})
@user_passes_test(lambda u: u.is_superuser)
def formats_delete(request, pk):
f = get_object_or_404(Formats, pk=pk)
f.delete()
return HttpResponse("Format deleted")
def formats_apply(request, pk):
format = get_object_or_404(Formats, pk=pk)
search_text = format.get_format()
entries = Entry.objects.filter(questions__icontains=search_text, inactive=False)
entry_list = []
for entry in entries:
entry_list.append((entry, entry.questions.replace(search_text, "")))
return render(
request,
"oef/formats_apply.html",
{"format": format, "entry_list": entry_list, "entries": entries},
)
def entry_detail_formats(request, pk):
entry = get_object_or_404(Entry, pk=pk)
formats = Formats.objects.all()
questions = entry.questions
matching_formats = []
for format in formats:
if format.get_format() in questions:
matching_formats.append(format)
matching_formats = sorted(matching_formats, key=lambda x: len(x.get_format()))
return render(
request,
"oef/entry_detail_formats.html",
{"entry": entry, "matching_formats": matching_formats},
)
def replace_questions(request):
if request.method == "POST":
search = request.POST.get("search")
replace = request.POST.get("replace")
if not search or not replace:
return HttpResponse("Please provide both search and replace values")
if request.POST.get("exact", False):
entries = Entry.objects.filter(questions=search, inactive=False)
formats = Formats.objects.filter(format=search)
else:
entries = Entry.objects.filter(questions__contains=search, inactive=False)
formats = Formats.objects.filter(format__contains=search)
for entry in entries:
entry.questions = entry.questions.replace(search, replace)
entry.save()
for format in formats:
format.format = format.format.replace(search, replace)
format.save()
return HttpResponse(f"{entries.count()} questions replaced")
else:
return render(request, "oef/replace_questions.html", {})
def entries_table(request):
entries = Entry.objects.filter(inactive=False).order_by("exam_code")
return render(request, "oef/entries_table.html", {"entries": entries})
def entries(request):
entries = Entry.objects.all().order_by("exam_code")
return render(request, "oef/entries.html", {"entries": entries})
def format_search(request):
if request.method == "POST":
search = request.POST.get("search")
entries = Entry.objects.filter(questions__icontains=search, inactive=False)
return render(request, "oef/format_search_results.html", {"entries": entries})
return render(
request,
"oef/format_search.html",
)
def subspecialties(request):
subspecialties = Subspecialty.objects.all()
format_map = []
for s in subspecialties:
format_map.append((s, s.formats_set.all()))
format_map.append(
("Nuclear Medicine", Formats.objects.filter(name__startswith="NM"))
)
return render(
request, "oef/subspecialties.html", context={"format_map": format_map}
)
def questions(request):
questions = set(
Entry.objects.filter(inactive=False).values_list("questions", flat=True)
)
questions = sorted(questions, key=lambda x: len(x))
questions_and_formats = []
for question in questions:
try:
format = Formats.objects.get(format=question)
except Formats.DoesNotExist:
format = None
except Formats.MultipleObjectsReturned:
format = Formats.objects.filter(format=question)
return HttpResponse(f"Multiple (duplicate) formats found [{",".join([f.name for f in format])}]")
questions_and_formats.append((question, format))
return render(
request,
"oef/questions.html",
{"questions": questions, "questions_and_formats": questions_and_formats},
)
def entries_by_question(request):
if request.method == "POST":
question = request.POST.get("question")
entries = Entry.objects.filter(questions=question, inactive=False)
return render(request, "oef/entries_by_question.html", {"entries": entries})
return HttpResponse("Please provide a question")
def entries_by_question_codes(request):
if request.method == "POST":
question = request.POST.get("question")
entries = Entry.objects.filter(questions=question, inactive=False)
return render(
request, "oef/entries_by_question_codes.html", {"entries": entries}
)
return HttpResponse("Please provide a question")
def questions_diff(request):
if request.method == "POST":
question1 = request.POST.get("question1", False)
question2 = request.POST.get("question2", False)
if not question1:
question1 = request.POST.get("search")
question2 = request.POST.get("replace")
html = HtmlDiff().make_table(question1.split("\n"), question2.split("\n"))
return HttpResponse(html)
return HttpResponse("Please provide two questions")
def questions_sym(request):
if request.method == "POST":
question = request.POST.get("question")
questions = set(
Entry.objects.filter(inactive=False).values_list("questions", flat=True)
)
output = []
for q in questions:
ratio = SequenceMatcher(None, question, q).ratio()
if ratio > 0.5:
output.append((q, ratio))
output = sorted(output, key=lambda x: x[1], reverse=True)
return render(request, "oef/questions_sym.html", {"output": output})
return HttpResponse("Please provide a question set")
def formats_save(request):
if request.method == "POST":
question = request.POST.get("question")
format_name = request.POST.get("format_name")
if not question:
return HttpResponse("Please provide a question")
if Formats.objects.filter(name=format_name).exists():
return HttpResponse("Format name already exists")
if Formats.objects.filter(format=question).exists():
return HttpResponse("Format questions already exists")
Formats.objects.create(name=format_name, format=question)
return HttpResponse("Format saved")
return HttpResponse("Please provide a question")