Amélioration de la recherche
This commit is contained in:
parent
5dd1125a68
commit
7097aa17d3
@ -298,9 +298,9 @@ article#filters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.helptext {
|
.helptext, .location-search {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
opacity: 0.7;
|
margin-top: -0.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.django-ckeditor-widget {
|
.django-ckeditor-widget {
|
||||||
@ -317,3 +317,15 @@ article#filters {
|
|||||||
.slide-buttons {
|
.slide-buttons {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
color: var(--primary);
|
||||||
|
font-weight: bold;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search .description {
|
||||||
|
margin-left: 1em;
|
||||||
|
font-size: 90%;
|
||||||
|
margin-top: -0.5em;
|
||||||
|
}
|
@ -1,41 +1,45 @@
|
|||||||
{% extends "agenda_culturel/page.html" %}
|
{% extends "agenda_culturel/page.html" %}
|
||||||
|
|
||||||
{% block title %}Rechercher un évnement{% endblock %}
|
{% block title %}Rechercher un événement{% endblock %}
|
||||||
|
|
||||||
|
{% load utils_extra %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
<article class="search">
|
||||||
<article>
|
|
||||||
<header>
|
<header>
|
||||||
<h1>Rechercher un événement</h1>
|
<h1>Rechercher un événement</h1>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<form method="get" class="form django-form" action="#results">
|
||||||
<form method="get" class="form django-form">
|
{{ filter.form }}
|
||||||
{% for field in filter.form %}
|
|
||||||
<div>
|
|
||||||
{{ field.errors }}
|
|
||||||
{{ field.label_tag }} {{ field }}
|
|
||||||
</div>
|
|
||||||
{% if forloop.first %}
|
|
||||||
<details>
|
|
||||||
<summary>Rechercher avancée</summary>
|
|
||||||
{% endif %}
|
|
||||||
{% if forloop.last %}
|
|
||||||
</details>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<button type="submit">Rechercher</button>
|
<button type="submit">Rechercher</button>
|
||||||
|
|
||||||
|
{% if full %}
|
||||||
|
<a href="{% url 'event_search' %}">Recherche simplifiée {% picto_from_name "chevron-right" %}</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{% url 'event_search_full' %}">Recherche avancée {% picto_from_name "chevron-right" %}</a>
|
||||||
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{% if has_results %}
|
||||||
|
<div id="results">
|
||||||
|
<p>{{ paginator_filter.paginator.count }} événement{{paginator_filter.object_list.count | pluralize }} correspond{{paginator_filter.object_list.count | pluralize:"ent" }} à la recherche.</p>
|
||||||
<ul>
|
<ul>
|
||||||
{% for obj in paginator_filter %}
|
{% for obj in paginator_filter %}
|
||||||
<li><a href="{{ obj.get_absolute_url }}">{{ obj }}</a></li>
|
<li><p>{% include "agenda_culturel/date-times-inc.html" with event=obj %}
|
||||||
{% endfor %}
|
: <a href="{{ obj.get_absolute_url }}">
|
||||||
</ul>
|
{% if obj.title_hl %}{{ obj.title_hl | safe }}{% else %}{{ obj.title }}{% endif %}</a></p>
|
||||||
<footer>
|
<p class="location-search">{% picto_from_name "map-pin" %}
|
||||||
|
{% if obj.location_hl %}{{ obj.location_hl | safe }}{% else %}{{ obj.location }}{% endif %}</p>
|
||||||
|
<div class="description">
|
||||||
|
{% if obj.description_hl %}{{ obj.description_hl | safe }}{% else %}{{ obj.description }}{% endif %}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% if paginator_filter.paginator.num_pages != 1 %}
|
||||||
|
<footer>
|
||||||
<span>
|
<span>
|
||||||
{% if paginator_filter.has_previous %}
|
{% if paginator_filter.has_previous %}
|
||||||
<a href="?page=1" role="button">« premier</a>
|
<a href="?page=1" role="button">« premier</a>
|
||||||
@ -51,7 +55,10 @@
|
|||||||
<a href="?page={{ paginator_filter.paginator.num_pages }}" role="button">dernier »</a>
|
<a href="?page={{ paginator_filter.paginator.num_pages }}" role="button">dernier »</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
</footer>
|
</footer>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -59,6 +59,10 @@ def url_day(d):
|
|||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def picto_from_name(name, datatooltip=""):
|
def picto_from_name(name, datatooltip=""):
|
||||||
return mark_safe('<span data-tooltip="' + datatooltip + '"><svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' + \
|
result = '<svg width="1em" height="1em" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' + \
|
||||||
'<use href="' + static("images/feather-sprite.svg") + '#' + name + '" />' + \
|
'<use href="' + static("images/feather-sprite.svg") + '#' + name + '" />' + \
|
||||||
'</svg></span>')
|
'</svg>'
|
||||||
|
if datatooltip != "":
|
||||||
|
result = '<span data-tooltip="' + datatooltip + '">' + result + '</span>'
|
||||||
|
|
||||||
|
return mark_safe(result)
|
||||||
|
@ -28,7 +28,8 @@ urlpatterns = [
|
|||||||
path("test_app/", include("test_app.urls")),
|
path("test_app/", include("test_app.urls")),
|
||||||
path("static-content/create", StaticContentCreateView.as_view(), name="create_static_content"),
|
path("static-content/create", StaticContentCreateView.as_view(), name="create_static_content"),
|
||||||
path("static-content/<int:pk>/edit", StaticContentUpdateView.as_view(), name="edit_static_content"),
|
path("static-content/<int:pk>/edit", StaticContentUpdateView.as_view(), name="edit_static_content"),
|
||||||
path('rechercher/', event_search, name='event_search')
|
path('rechercher/', event_search, name='event_search'),
|
||||||
|
path('rechercher/complet/', event_search_full, name='event_search_full')
|
||||||
]
|
]
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
@ -4,6 +4,8 @@ from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.http import QueryDict
|
from django.http import QueryDict
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.contrib.postgres.search import SearchQuery, SearchHeadline
|
||||||
|
|
||||||
|
|
||||||
from .forms import EventSubmissionModelForm
|
from .forms import EventSubmissionModelForm
|
||||||
from .celery import create_event_from_submission
|
from .celery import create_event_from_submission
|
||||||
@ -403,16 +405,34 @@ def event_list(request):
|
|||||||
return render(request, 'agenda_culturel/list.html', {'filter': filter, 'paginator_filter': response})
|
return render(request, 'agenda_culturel/list.html', {'filter': filter, 'paginator_filter': response})
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleSearchEventFilter(django_filters.FilterSet):
|
||||||
|
q = django_filters.CharFilter(method='custom_filter', label=_("Search"))
|
||||||
|
|
||||||
|
def custom_filter(self, queryset, name, value):
|
||||||
|
search_query = SearchQuery(value, config='french')
|
||||||
|
qs = queryset.filter(
|
||||||
|
Q(title__contains=value) | Q(location__contains=value) | Q(description__contains=value))
|
||||||
|
for f in ["title", "location", "description"]:
|
||||||
|
params = { f + "_hl": SearchHeadline(f,
|
||||||
|
search_query,
|
||||||
|
start_sel="<span class=\"highlight\">",
|
||||||
|
stop_sel="</span>",
|
||||||
|
config='french')}
|
||||||
|
qs = qs.annotate(**params)
|
||||||
|
return qs
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Event
|
||||||
|
fields = ['q']
|
||||||
|
|
||||||
|
|
||||||
class SearchEventFilter(django_filters.FilterSet):
|
class SearchEventFilter(django_filters.FilterSet):
|
||||||
tags = django_filters.CharFilter(lookup_expr='icontains')
|
tags = django_filters.CharFilter(lookup_expr='icontains')
|
||||||
title = django_filters.CharFilter(lookup_expr='contains')
|
title = django_filters.CharFilter(method="hl_filter_contains")
|
||||||
location = django_filters.CharFilter(lookup_expr='contains')
|
location = django_filters.CharFilter(method="hl_filter_contains")
|
||||||
description = django_filters.CharFilter(lookup_expr='contains')
|
description = django_filters.CharFilter(method="hl_filter_contains")
|
||||||
start_day = django_filters.DateFromToRangeFilter(widget=django_filters.widgets.RangeWidget(attrs={'type': 'date'}))
|
start_day = django_filters.DateFromToRangeFilter(widget=django_filters.widgets.RangeWidget(attrs={'type': 'date'}))
|
||||||
|
|
||||||
q = django_filters.CharFilter(method='custom_filter', label=_("Search"))
|
|
||||||
|
|
||||||
o = django_filters.OrderingFilter(
|
o = django_filters.OrderingFilter(
|
||||||
# tuple-mapping retains order
|
# tuple-mapping retains order
|
||||||
fields=(
|
fields=(
|
||||||
@ -422,18 +442,36 @@ class SearchEventFilter(django_filters.FilterSet):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def custom_filter(self, queryset, name, value):
|
def hl_filter_contains(self, queryset, name, value):
|
||||||
return queryset.filter(
|
|
||||||
Q(title__contains=value) | Q(location__contains=value) | Q(description__contains=value))
|
# first check if it contains
|
||||||
|
filter_contains = { name + "__contains": value }
|
||||||
|
queryset = queryset.filter(**filter_contains)
|
||||||
|
|
||||||
|
# then hightlight the result
|
||||||
|
search_query = SearchQuery(value, config='french')
|
||||||
|
params = { name + "_hl": SearchHeadline(name,
|
||||||
|
search_query,
|
||||||
|
start_sel="<span class=\"highlight\">",
|
||||||
|
stop_sel="</span>",
|
||||||
|
config='french')}
|
||||||
|
return queryset.annotate(**params)
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Event
|
model = Event
|
||||||
fields = ['q', 'title', 'location', 'description', 'category', 'tags', 'start_day']
|
fields = ['title', 'location', 'description', 'category', 'tags', 'start_day']
|
||||||
|
|
||||||
|
|
||||||
def event_search(request):
|
|
||||||
|
def event_search(request, full=False):
|
||||||
|
|
||||||
|
if full:
|
||||||
filter = SearchEventFilter(request.GET, queryset=get_event_qs(request).order_by("-start_day"))
|
filter = SearchEventFilter(request.GET, queryset=get_event_qs(request).order_by("-start_day"))
|
||||||
|
else:
|
||||||
|
filter = SimpleSearchEventFilter(request.GET, queryset=get_event_qs(request).order_by("-start_day"))
|
||||||
|
|
||||||
|
|
||||||
paginator = Paginator(filter.qs, 10)
|
paginator = Paginator(filter.qs, 10)
|
||||||
page = request.GET.get('page')
|
page = request.GET.get('page')
|
||||||
|
|
||||||
@ -444,4 +482,10 @@ def event_search(request):
|
|||||||
except EmptyPage:
|
except EmptyPage:
|
||||||
response = paginator.page(paginator.num_pages)
|
response = paginator.page(paginator.num_pages)
|
||||||
|
|
||||||
return render(request, 'agenda_culturel/search.html', {'filter': filter, 'paginator_filter': response})
|
return render(request, 'agenda_culturel/search.html', {'filter': filter,
|
||||||
|
'has_results': len(request.GET) != 0 or (len(request.GET) > 1 and "page" in request.GET),
|
||||||
|
'paginator_filter': response,
|
||||||
|
'full': full})
|
||||||
|
|
||||||
|
def event_search_full(request):
|
||||||
|
return event_search(request, True)
|
||||||
|
Loading…
Reference in New Issue
Block a user