Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add search functionality #117

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ footer .container {
padding-right: 1rem;
color: #a0aec0;
margin-bottom: 0;
text-align: right;
text-align: left;
align-items: center;
}

Expand Down
1 change: 1 addition & 0 deletions suministrospr/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Common(Configuration):
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.postgres",
"whitenoise.runserver_nostatic",
"django.contrib.staticfiles",
"django_extensions",
Expand Down
5 changes: 4 additions & 1 deletion suministrospr/suministros/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ def clean_content(self):


class FilterForm(forms.Form):
q = forms.CharField(label="Busqueda", required=False)
tag = forms.ModelChoiceField(
queryset=Tag.objects.all().order_by("name"), to_field_name="slug"
queryset=Tag.objects.all().order_by("name"),
to_field_name="slug",
required=False,
)
34 changes: 20 additions & 14 deletions suministrospr/suministros/templates/suministros/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,26 @@
{% block content %}
<div class="main__search">
<div class="main__search--header">
<form action="{% url 'suministro-search' %}" method="GET">
<div class="main__actions--form">
<div class="search__header--container">
<label for="inline-full-name">
{% trans 'Resultados para categoría' %}
</label>
<div class="relative">
<select name="tag" onchange="this.form.submit()">
{% for value, label in filter_form.fields.tag.choices %}
<option value="{{ value }}" {% if filter_form.tag.value == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<div class="svg">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>
<form action="{% url 'suministro-search' %}" method="GET">
<div class="main__actions--form">
<div class="search__header--container">
<div class="input__container">
<label>{% trans Busqueda %}</label>
<input type="text" name="q" value=""/>
<div class="relative">
<select name="tag">
<option value="">{% trans Filtrar por categoría %}</option>
{% for value, label in filter_form.fields.tag.choices %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
</select>
<div class="svg">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>
</div>
</div>
<div class="main__search--button">
<button type="submit">Buscar</button>
</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,39 @@
</div>
</div>
<div class="main__about main__about--actions">

<div class="main__about--button">
<a href="{% url 'suministro-add' %}">
<svg class="fill-current w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21 21"><path class="heroicon-ui" d="M5 3h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2zm0 2v14h14V5H5zm8 6h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0v-2H9a1 1 0 0 1 0-2h2V9a1 1 0 0 1 2 0v2z"/></svg>
<span>{% trans 'Añadir sector o refugio' %}</span>
</a>
</div>

<form action="{% url 'suministro-search' %}" method="GET">
<div class="main__actions--form">
<div class="actions__form--container">
<div class="relative">
<select name="tag" onchange="this.form.submit()">
<option value="">{% trans 'Filtrar por categoría' %}</option>
{% for value, label in filter_form.fields.tag.choices %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
</select>
<div class="svg">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>
</div>
<div class="input__container">
<label>{% Busqueda %}</label>
<input type="text" name="q" value=""/>
<div class="relative">
<select name="tag">
<option value="">{% trans Filtrar por categoría %}</option>
{% for value, label in filter_form.fields.tag.choices %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
</select>
<div class="svg">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"/></svg>
</div>
</div>
<div class="main__search--button">
<button type="submit">Buscar</button>
</div>
</div>
</div>
</div>
</form>

</div>

<div class="main__about main__about--actions">
<div class="main__about--button">
<a href="{% url 'suministro-add' %}">
<svg class="fill-current w-4 h-4 mr-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21 21"><path class="heroicon-ui" d="M5 3h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5c0-1.1.9-2 2-2zm0 2v14h14V5H5zm8 6h2a1 1 0 0 1 0 2h-2v2a1 1 0 0 1-2 0v-2H9a1 1 0 0 1 0-2h2V9a1 1 0 0 1 2 0v2z"/></svg>
<span>Añadir sector o refugio</span>
</a>
</div>
</div>
<div class="main__munigrid">

<div class="main__munigrid main__munigrid--container">
Expand Down
25 changes: 17 additions & 8 deletions suministrospr/suministros/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from reversion.views import RevisionMixin

from ..utils.mixins import CacheMixin
from ..utils.search import search
from .constants import MUNICIPALITIES
from .forms import FilterForm, SuministroModelForm
from .models import Municipality, Suministro
Expand Down Expand Up @@ -98,9 +99,12 @@ class SuministroSearch(CacheMixin, TemplateView):
def get_cache_key(self):
cache_key = self.cache_key
tag = self.request.GET.get("tag")
query = self.request.GET.get("q")

if tag:
cache_key = f"{cache_key}:{tag}"
if query:
cache_key = f"{cache_key}:{query}"

return cache_key

Expand All @@ -110,8 +114,7 @@ def get_context_data(self):
data["results_municipalities"] = 0
data["results"] = []

filter_form = FilterForm(self.request.GET)

form = FilterForm(self.request.GET)
suministros = Suministro.objects.all().defer("content").order_by("title")

municipalities_with_suministros = (
Expand All @@ -121,22 +124,28 @@ def get_context_data(self):
.filter(suministro_count__gt=0)
.order_by("-suministro_count")
)
if form.is_valid():
query = None
tag_slug = None

if "q" in self.request.GET:
query = form.cleaned_data["q"]
if "tag" in self.request.GET:
tag_slug = form.cleaned_data["tag"]

if filter_form.is_valid():
tag_slug = filter_form.cleaned_data["tag"]
suministros = suministros.filter(tags__slug=tag_slug)
suministros = search(query, tag_slug, suministros)

municipalities_with_suministros = (
Municipality.objects.all()
.prefetch_related(Prefetch("suministros", queryset=suministros))
.annotate(
suministro_count=Count(
"suministro",
filter=Q(suministro__tags__slug=tag_slug),
filter=Q(suministro__in=suministros),
distinct=True,
)
)
.filter(suministro_count__gt=0, suministro__tags__slug=tag_slug)
.filter(suministro_count__gt=0, suministro__in=suministros)
.order_by("-suministro_count")
)

Expand All @@ -151,7 +160,7 @@ def get_context_data(self):
}
)

data["filter_form"] = filter_form
data["filter_form"] = form

return data

Expand Down
30 changes: 30 additions & 0 deletions suministrospr/utils/search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector

suministros_search_vector = (
SearchVector("title", weight="B")
+ SearchVector("content", weight="A")
+ SearchVector("municipality__name", weight="C")
+ SearchVector("tags__name", weight="C")
)

municipality_search_vector = SearchVector("name")
tags_search_vector = SearchVector("name")


def search(query, tag_slug, suministros):
if tag_slug:
suministros = suministros.filter(tags__slug=tag_slug)

if query:
keyword_search_query = SearchQuery(query)
phrase_search_query = SearchQuery(query, search_type="phrase")
final_search_query = keyword_search_query | phrase_search_query
search_rank = SearchRank(suministros_search_vector, final_search_query)

suministros = (
suministros.annotate(search=suministros_search_vector, rank=search_rank)
.filter(search=final_search_query)
.order_by("-rank")
)

return suministros.distinct()