improve event organizer search

This commit is contained in:
2026-07-05 17:53:33 +02:00
parent e57eb48c88
commit 36c01902a1
4 changed files with 78 additions and 2 deletions
+1 -1
View File
@@ -164,7 +164,7 @@ class EventOrganizerLink(Orderable):
]
@register_snippet
# registered as a snippet via EventOrganizerSnippetViewSet in wagtail_hooks.py
@register_query_field("eventOrganizer", "eventOrganizers")
class EventOrganizer(index.Indexed, ClusterableModel):
objects = WPAwareManager()
+44
View File
@@ -1,11 +1,53 @@
from django import forms
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from wagtail.admin.forms import WagtailAdminModelForm
from wagtail.admin.forms.choosers import BaseFilterForm
from wagtail.admin.views.generic.chooser import ChooseResultsView, ChooseView
from wagtail.admin.viewsets.chooser import ChooserViewSet
from wagtail.snippets.views.snippets import SnippetViewSet
from dnscms.utils import slugify
from events.models import EventOrganizer
class EventOrganizerSearchForm(BaseFilterForm):
"""Substring search on name/slug"""
q = forms.CharField(
label=_("Search term"),
widget=forms.TextInput(attrs={"placeholder": _("Search")}),
required=False,
)
def filter(self, objects):
objects = super().filter(objects)
search_query = self.cleaned_data.get("q")
if search_query:
objects = objects.filter(
Q(name__icontains=search_query) | Q(slug__icontains=search_query)
)
self.is_searching = True
self.search_query = search_query
return objects
class EventOrganizerChooseView(ChooseView):
filter_form_class = EventOrganizerSearchForm
class EventOrganizerChooseResultsView(ChooseResultsView):
filter_form_class = EventOrganizerSearchForm
class EventOrganizerSnippetViewSet(SnippetViewSet):
model = EventOrganizer
icon = "group"
# unset the search backend so the listing search filters on icontains instead
search_backend_name = None
search_fields = ["name", "slug"]
class EventOrganizerCreationForm(WagtailAdminModelForm):
class Meta:
model = EventOrganizer
@@ -29,6 +71,8 @@ class EventOrganizerChooserViewSet(ChooserViewSet):
choose_another_text = _("Choose another organizer")
edit_item_text = _("Edit this organizer")
creation_form_class = EventOrganizerCreationForm
choose_view_class = EventOrganizerChooseView
choose_results_view_class = EventOrganizerChooseResultsView
event_organizer_chooser_viewset = EventOrganizerChooserViewSet("event_organizer_chooser")
+4 -1
View File
@@ -3,10 +3,13 @@ from django.utils.translation import gettext_lazy as _
from wagtail import hooks
from wagtail.admin.auth import user_passes_test
from wagtail.admin.menu import MenuItem
from wagtail.snippets.models import register_snippet
from .admin import event_sidebar_viewset, event_explorer_viewset
from .merge_organizers import MergeOrganizersConfirmView, MergeOrganizersSelectView
from .views import event_organizer_chooser_viewset
from .views import EventOrganizerSnippetViewSet, event_organizer_chooser_viewset
register_snippet(EventOrganizerSnippetViewSet)
superuser_only = user_passes_test(lambda user: user.is_superuser)
+29
View File
@@ -4,6 +4,7 @@ import pytest
from django.core.exceptions import ValidationError
from django.db import connection
from django.test.utils import CaptureQueriesContext
from django.urls import reverse
from django.utils import timezone
from events.admin import EventDateColumn, OrganizersColumn
@@ -572,3 +573,31 @@ def test_graphql_event_index_returns_all_fields_for_comprehensive_event(
assert datetime.fromisoformat(venue_occ["end"]) == venue_occ_db.end
assert datetime.fromisoformat(custom_occ["start"]) == custom_occ_db.start
assert datetime.fromisoformat(custom_occ["end"]) == custom_occ_db.end
@pytest.fixture
def searchable_organizers(db):
return [
EventOrganizer.objects.create(name="Arrangementsutvalget", slug="arrangementsutvalget"),
EventOrganizer.objects.create(name="Cinema Neuf", slug="kino"),
]
@pytest.mark.parametrize(
"url_name",
["event_organizer_chooser:choose", "wagtailsnippets_events_eventorganizer:list"],
)
def test_organizer_search_matches_substrings_of_name_and_slug(
admin_client, searchable_organizers, url_name
):
url = reverse(url_name)
# mid-word match inside a compound name
content = admin_client.get(url, {"q": "utvalget"}).content.decode()
assert "Arrangementsutvalget" in content
assert "Cinema Neuf" not in content
# slug-only match
content = admin_client.get(url, {"q": "kino"}).content.decode()
assert "Cinema Neuf" in content
assert "Arrangementsutvalget" not in content