improve event organizer search
This commit is contained in:
@@ -164,7 +164,7 @@ class EventOrganizerLink(Orderable):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@register_snippet
|
# registered as a snippet via EventOrganizerSnippetViewSet in wagtail_hooks.py
|
||||||
@register_query_field("eventOrganizer", "eventOrganizers")
|
@register_query_field("eventOrganizer", "eventOrganizers")
|
||||||
class EventOrganizer(index.Indexed, ClusterableModel):
|
class EventOrganizer(index.Indexed, ClusterableModel):
|
||||||
objects = WPAwareManager()
|
objects = WPAwareManager()
|
||||||
|
|||||||
@@ -1,11 +1,53 @@
|
|||||||
|
from django import forms
|
||||||
|
from django.db.models import Q
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from wagtail.admin.forms import WagtailAdminModelForm
|
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.admin.viewsets.chooser import ChooserViewSet
|
||||||
|
from wagtail.snippets.views.snippets import SnippetViewSet
|
||||||
|
|
||||||
from dnscms.utils import slugify
|
from dnscms.utils import slugify
|
||||||
from events.models import EventOrganizer
|
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 EventOrganizerCreationForm(WagtailAdminModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = EventOrganizer
|
model = EventOrganizer
|
||||||
@@ -29,6 +71,8 @@ class EventOrganizerChooserViewSet(ChooserViewSet):
|
|||||||
choose_another_text = _("Choose another organizer")
|
choose_another_text = _("Choose another organizer")
|
||||||
edit_item_text = _("Edit this organizer")
|
edit_item_text = _("Edit this organizer")
|
||||||
creation_form_class = EventOrganizerCreationForm
|
creation_form_class = EventOrganizerCreationForm
|
||||||
|
choose_view_class = EventOrganizerChooseView
|
||||||
|
choose_results_view_class = EventOrganizerChooseResultsView
|
||||||
|
|
||||||
|
|
||||||
event_organizer_chooser_viewset = EventOrganizerChooserViewSet("event_organizer_chooser")
|
event_organizer_chooser_viewset = EventOrganizerChooserViewSet("event_organizer_chooser")
|
||||||
|
|||||||
@@ -3,10 +3,13 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from wagtail import hooks
|
from wagtail import hooks
|
||||||
from wagtail.admin.auth import user_passes_test
|
from wagtail.admin.auth import user_passes_test
|
||||||
from wagtail.admin.menu import MenuItem
|
from wagtail.admin.menu import MenuItem
|
||||||
|
from wagtail.snippets.models import register_snippet
|
||||||
|
|
||||||
from .admin import event_sidebar_viewset, event_explorer_viewset
|
from .admin import event_sidebar_viewset, event_explorer_viewset
|
||||||
from .merge_organizers import MergeOrganizersConfirmView, MergeOrganizersSelectView
|
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)
|
superuser_only = user_passes_test(lambda user: user.is_superuser)
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import pytest
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import connection
|
from django.db import connection
|
||||||
from django.test.utils import CaptureQueriesContext
|
from django.test.utils import CaptureQueriesContext
|
||||||
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from events.admin import EventDateColumn, OrganizersColumn
|
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(venue_occ["end"]) == venue_occ_db.end
|
||||||
assert datetime.fromisoformat(custom_occ["start"]) == custom_occ_db.start
|
assert datetime.fromisoformat(custom_occ["start"]) == custom_occ_db.start
|
||||||
assert datetime.fromisoformat(custom_occ["end"]) == custom_occ_db.end
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user