Add basic search for govplans

This commit is contained in:
Stefan Wehrmeyer 2022-03-14 13:42:08 +01:00
parent be6717c2a0
commit 2b6a1805dd
4 changed files with 85 additions and 2 deletions

View file

@ -1,5 +1,9 @@
import functools
import re
from django.conf import settings
from django.contrib.auth.models import Group
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
from django.db import models
from django.urls import reverse
from django.utils import timezone
@ -84,6 +88,48 @@ class CategorizedGovernmentPlan(TaggedItemBase):
verbose_name_plural = _("Categorized Government Plans")
WORD_RE = re.compile(r"^\w+$", re.IGNORECASE)
class GovernmentPlanManager(models.Manager):
SEARCH_LANG = "german"
def get_search_vector(self):
fields = [
("title", "A"),
("description", "B"),
("quote", "B"),
]
return functools.reduce(
lambda a, b: a + b,
[SearchVector(f, weight=w, config=self.SEARCH_LANG) for f, w in fields],
)
def search(self, query, qs=None):
if not qs:
qs = self.get_queryset()
if not query:
return qs
search_queries = []
for q in query.split():
if WORD_RE.match(q):
sq = SearchQuery(
"{}:*".format(q), search_type="raw", config=self.SEARCH_LANG
)
else:
sq = SearchQuery(q, search_type="plain", config=self.SEARCH_LANG)
search_queries.append(sq)
search_query = functools.reduce(lambda a, b: a & b, search_queries)
search_vector = self.get_search_vector()
qs = (
qs.annotate(rank=SearchRank(search_vector, search_query))
.filter(rank__gte=0.3)
.order_by("-rank")
)
return qs
class GovernmentPlan(models.Model):
government = models.ForeignKey(
Government, on_delete=models.CASCADE, verbose_name=_("government")
@ -142,6 +188,8 @@ class GovernmentPlan(models.Model):
Group, null=True, blank=True, on_delete=models.SET_NULL, verbose_name=_("group")
)
objects = GovernmentPlanManager()
class Meta:
ordering = ("reference", "title")
verbose_name = _("Government plan")
@ -313,6 +361,7 @@ if CMSPlugin:
("froide_govplan/plugins/default.html", _("Normal")),
("froide_govplan/plugins/progress.html", _("Progress")),
("froide_govplan/plugins/card_cols.html", _("Card columns")),
("froide_govplan/plugins/search.html", _("Search")),
]
class GovernmentPlansCMSPlugin(CMSPlugin):

View file

@ -0,0 +1,17 @@
{% load i18n %}
<form method="get" action="{% url 'govplan:search' %}" class="ajaxified" data-container="#govplan-searchresult-{{ instance.id }}">
<div class="input-group mb-3">
<input type="text" name="q" class="form-control" aria-label="{% translate 'search query' %}">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="submit">
{% translate "Search" %}
</button>
</div>
</div>
{% if instance.government_id %}
<input type="hidden" name="government" value="{{ instance.government_id }}"/>
{% endif %}
</form>
<div id="govplan-searchresult-{{ instance.id }}">
</div>

View file

@ -2,12 +2,13 @@ from django.urls import path
from django.utils.translation import pgettext_lazy
from .admin import govplan_admin_site
from .views import GovPlanDetailView, GovPlanSectionDetailView
from .views import GovPlanDetailView, GovPlanSectionDetailView, search
app_name = "govplan"
urlpatterns = [
path("admin/", govplan_admin_site.urls),
path("search/", search, name="search"),
path(
pgettext_lazy("url part", "<slug:gov>/plan/<slug:plan>/"),
GovPlanDetailView.as_view(),

View file

@ -1,4 +1,4 @@
from django.shortcuts import get_object_or_404
from django.shortcuts import get_object_or_404, render
from django.views.generic import DetailView
from .models import Government, GovernmentPlan, GovernmentPlanSection
@ -53,3 +53,19 @@ class GovPlanDetailView(GovernmentMixin, DetailView):
"-timestamp"
)
return context
def search(request):
plans = GovernmentPlan.objects.search(request.GET.get("q", ""))
if request.GET.get("government"):
try:
gov_id = int(request.GET["government"])
plans = plans.filter(government_id=gov_id)
except ValueError:
pass
plans = plans[:20]
return render(
request, "froide_govplan/plugins/card_cols.html", {"object_list": plans}
)