1
0
Fork 0
mirror of https://github.com/Findus23/RPGnotes.git synced 2024-09-19 15:43:45 +02:00
RPGnotes/search/views.py

102 lines
3.7 KiB
Python
Raw Permalink Normal View History

2022-04-11 22:43:06 +02:00
# Create your views here.
from itertools import chain
2022-04-11 23:52:19 +02:00
from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank, SearchHeadline, TrigramWordDistance
2022-11-19 17:06:20 +01:00
from django.db.models import Func, F
2022-04-11 23:52:19 +02:00
from django.http import JsonResponse
2022-04-11 22:43:06 +02:00
from django.views.generic import TemplateView
from campaigns.models import Campaign
from characters.models import Character
from days.models import IngameDay
from factions.models import Faction
from locations.models import Location
from loot.models import Loot
from notes.models import Note
2022-04-11 23:52:19 +02:00
search_models = [Location, Character, Faction, IngameDay, Note, Loot]
2022-04-11 22:43:06 +02:00
class SearchResultsView(TemplateView):
template_name = "search/search_results.jinja"
def get_context_data(self, **kwargs):
if "q" not in self.request.GET:
return ""
query_string = self.request.GET['q']
2023-04-25 22:16:28 +02:00
context = super().get_context_data(**kwargs)
2022-04-11 22:43:06 +02:00
campaign: Campaign = self.request.tenant
config = campaign.language
name_vector = SearchVector('name', weight="A", config=config)
description_vector = SearchVector("description_html", weight="B", config=config)
query = SearchQuery(query_string, search_type='websearch', config=config)
all_results = []
all_similar = []
2022-04-11 23:52:19 +02:00
for m in search_models:
2022-04-11 22:43:06 +02:00
if m == IngameDay:
vector = description_vector
else:
vector = description_vector + name_vector
similar = m.objects.annotate(
2022-04-11 23:52:19 +02:00
distance=TrigramWordDistance(query_string, "name")
2022-04-11 22:51:24 +02:00
# distance=TrigramDistance("name", query_string)
).filter(name__trigram_word_similar=query_string).order_by('distance')
2022-04-11 22:43:06 +02:00
all_similar.extend(list(similar))
results = m.objects.annotate(
search=vector,
rank=SearchRank(vector, query),
headline=SearchHeadline(
'description_html',
query,
start_sel='<strong>',
stop_sel='</strong>',
),
).filter(search=query).order_by('-rank')
all_results.append(results)
context["results"] = chain(*all_results)
all_similar.sort(key=lambda s: s.distance)
all_similar = [s for s in all_similar if s.distance != 0]
context["similars"] = all_similar
context["query"] = query_string
return context
2022-04-11 23:52:19 +02:00
def autocomplete(request):
if "q" not in request.GET:
return ""
query_string = request.GET['q']
all_similar = []
for m in search_models:
if m == IngameDay:
continue
similar = m.objects.annotate(
distance=TrigramWordDistance(query_string, "name")
# distance=TrigramDistance("name", query_string)
).order_by('distance')
2022-04-11 23:57:49 +02:00
similar = [s for s in similar if s.distance <= 0.5]
2022-04-11 23:52:19 +02:00
all_similar.extend(list(similar))
2022-11-19 17:06:20 +01:00
similar_aliases = m.objects.annotate(
alias=Func(F("aliases"), function="unnest")
).annotate(
distance=TrigramWordDistance(query_string, "alias")
# distance=TrigramDistance("name", query_string)
).order_by('distance')
print("sim", similar_aliases)
similar_aliases = [s for s in similar_aliases if s.distance <= 0.5]
all_similar.extend(list(similar_aliases))
2022-04-11 23:52:19 +02:00
all_similar.sort(key=lambda s: s.distance)
data = []
for s in all_similar:
2022-11-19 17:06:20 +01:00
if hasattr(s, "alias"):
name = f"{s.alias} ({s.name})"
else:
name = s.name
2022-04-11 23:52:19 +02:00
data.append({
"url": s.get_absolute_url(),
2022-11-19 17:06:20 +01:00
"name": name,
2022-04-11 23:52:19 +02:00
"distance": s.distance
})
return JsonResponse(data, safe=False)