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
|
|
|
|
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']
|
|
|
|
context = super(SearchResultsView, self).get_context_data(**kwargs)
|
|
|
|
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))
|
|
|
|
all_similar.sort(key=lambda s: s.distance)
|
|
|
|
data = []
|
|
|
|
for s in all_similar:
|
|
|
|
data.append({
|
|
|
|
"url": s.get_absolute_url(),
|
|
|
|
"name": s.name,
|
|
|
|
"distance": s.distance
|
|
|
|
})
|
|
|
|
return JsonResponse(data, safe=False)
|