drugs/core/views/search.py

255 lines
8.7 KiB
Python
Raw Normal View History

2024-03-26 17:06:44 +00:00
import urllib
import uuid
2024-03-26 17:06:44 +00:00
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
2024-03-26 17:06:44 +00:00
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render
2024-03-26 17:06:44 +00:00
from django.urls import reverse
from django.views import View
2024-03-26 17:06:44 +00:00
from django_tables2 import SingleTableView
from mixins.views import (
ObjectCreate,
ObjectDelete,
ObjectList,
ObjectRead,
ObjectUpdate,
)
2024-03-26 17:06:44 +00:00
from core import db
from core.models import Drug
2024-03-26 17:06:44 +00:00
from core.views.ui.tables import DrugsTable
2024-03-26 17:06:44 +00:00
def make_table(context):
object_list = [x.__dict__ for x in context["object_list"]]
table = DrugsTable(object_list)
context["table"] = table
# del context["results"]
return context
2024-03-26 17:06:44 +00:00
def parse_dates(dates):
spl = dates.split(" - ")
if all(spl):
spl = [f"{x.replace(' ', 'T')}" for x in spl]
if not len(spl) == 2:
message = "Invalid dates"
message_class = "danger"
return {"message": message, "class": message_class}
from_ts, to_ts = spl
from_date, from_time = from_ts.split("T")
to_date, to_time = to_ts.split("T")
2024-03-26 17:06:44 +00:00
return {
"from_date": from_date,
"to_date": to_date,
"from_time": from_time,
"to_time": to_time,
}
def create_tags(query):
"""
Grab the tags out of the query and make a list
we can add to the Bulma tags element when the page loads.
"""
spl = query.split("AND")
spl = [x.strip() for x in spl if ":" in x]
spl = [x.replace('"', "") for x in spl]
tags = [f"{tag}: {elem}" for tag, elem in [x.split(":")[:2] for x in spl]]
return tags
def parse_tags(tags_pre):
"""
Parse the tags from the variable tags_pre.
"""
tags = []
tags_spl = tags_pre.split(",")
if tags_spl:
for tag in tags_spl:
tag = tag.split(": ")
if len(tag) == 2:
key, val = tag
tags.append({key: val})
return tags
class DrugsTableView(SingleTableView):
table_class = DrugsTable
template_name = "mixins/wm/widget.html"
window_content = "window-content/results.html"
# htmx_partial = "partials/"
paginate_by = settings.DRUGS_RESULTS_PER_PAGE
widget_options = 'gs-w="10" gs-h="1" gs-y="10" gs-x="1"'
def common_request(self, request, **kwargs):
extra_params = {}
if request.user.is_anonymous:
sizes = settings.MAIN_SIZES_ANON
else:
sizes = settings.MAIN_SIZES
if request.GET:
self.template_name = "index.html"
# GET arguments in URL like ?query=xyz
query_params = request.GET.dict()
if request.htmx:
if request.resolver_match.url_name == "search_partial":
self.template_name = "partials/results_table.html"
elif request.POST:
query_params = request.POST.dict()
else:
self.template_name = "index.html"
# No query, this is a fresh page load
# Don't try to search, since there's clearly nothing to do
params_with_defaults = {}
db.add_defaults(params_with_defaults)
context = {
"sizes": sizes,
"params": params_with_defaults,
"unique": "results",
"widget_options": self.widget_options,
"window_content": self.window_content,
"title": "Results",
}
return render(request, self.template_name, context)
# Merge everything together just in case
tmp_post = request.POST.dict()
tmp_get = request.GET.dict()
tmp_post = {k: v for k, v in tmp_post.items() if v and not v == "None"}
tmp_get = {k: v for k, v in tmp_get.items() if v and not v == "None"}
query_params.update(tmp_post)
query_params.update(tmp_get)
# URI we're passing to the template for linking
if "csrfmiddlewaretoken" in query_params:
del query_params["csrfmiddlewaretoken"]
# Parse the dates
if "dates" in query_params:
dates = parse_dates(query_params["dates"])
del query_params["dates"]
if dates:
if "message" in dates:
return render(request, self.template_name, dates)
query_params["from_date"] = dates["from_date"]
query_params["to_date"] = dates["to_date"]
query_params["from_time"] = dates["from_time"]
query_params["to_time"] = dates["to_time"]
# Remove null values
if "query" in query_params:
if query_params["query"] == "":
del query_params["query"]
# Remove null tags values
# TODO: TAGS
if "tags" in query_params:
if query_params["tags"] == "":
del query_params["tags"]
else:
# Parse the tags and populate cast to pass to search function
tags = parse_tags(query_params["tags"])
extra_params["tags"] = tags
context = db.orm.drug_query(request, query_params, **extra_params)
print("CONTEXT", context)
# Unique is for identifying the widgets.
# We don't want a random one since we only want one results pane.
context["unique"] = "results"
context["window_content"] = self.window_content
context["widget_options"] = self.widget_options
context["title"] = "Results"
# Valid sizes
context["sizes"] = sizes
# Add any default parameters to the context
params_with_defaults = dict(query_params)
db.add_defaults(params_with_defaults)
context["params"] = params_with_defaults
# Remove anything that we or the user set to a default for
# pretty URLs
db.remove_defaults(query_params)
url_params = urllib.parse.urlencode(query_params)
context["client_uri"] = url_params
# There's an error
if "message" in context:
response = render(request, self.template_name, context)
# Still push the URL so they can share it to get assistance
if request.GET:
if request.htmx:
response["HX-Replace-Url"] = reverse("home") + "?" + url_params
elif request.POST:
response["HX-Replace-Url"] = reverse("home") + "?" + url_params
return response
# Create data for chart.js sentiment graph
# graph = make_graph(context["object_list"])
# context["data"] = graph
# Create the table
context = make_table(context)
print("CONTEXT", context)
# URI we're passing to the template for linking, table fields removed
table_fields = ["page", "sort"]
clean_params = {k: v for k, v in query_params.items() if k not in table_fields}
clean_url_params = urllib.parse.urlencode(clean_params)
context["uri"] = clean_url_params
# unique = str(uuid.uuid4())[:8]
# self.context = context
return context
def get(self, request, *args, **kwargs):
print("GET")
self.context = self.common_request(request)
if isinstance(self.context, HttpResponse):
return self.context
self.object_list = self.context["object_list"]
show = []
show = set().union(
*([x.name for x in d._meta.get_fields()] for d in self.object_list)
)
allow_empty = self.get_allow_empty()
if not allow_empty:
# When pagination is enabled and object_list is a queryset,
# it's better to do a cheap query than to load the unpaginated
# queryset in memory.
if self.get_paginate_by(self.object_list) is not None and hasattr(
self.object_list, "exists"
):
is_empty = not self.object_list.exists() # noqa
else:
is_empty = not self.object_list # noqa
context = self.get_context_data()
for k, v in self.context.items():
if k not in context:
context[k] = v
context["show"] = show
# if request.htmx:
# self.template_name = self.window_content
# if request.method == "GET":
# if not request.htmx:
# self.template_name = "ui/drilldown/drilldown.html"
response = self.render_to_response(context)
# if not request.method == "GET":
if "client_uri" in context:
response["HX-Replace-Url"] = reverse("home") + "?" + context["client_uri"]
return response
def post(self, request, *args, **kwargs):
return self.get(request, *args, **kwargs)