Allow customising the search_fields and search backend to use via SnippetViewSet (#10290)

pull/8345/head
Sage Abdullah 2023-03-29 15:40:57 +01:00 zatwierdzone przez Matt Westcott
rodzic 3965ceedfa
commit 167471b1f7
7 zmienionych plików z 93 dodań i 2 usunięć

Wyświetl plik

@ -40,6 +40,7 @@ Changelog
* Allow overriding the base queryset to be used in snippet `IndexView` (Sage Abdullah)
* Revise alignment and spacing of form fields and sections (Thibaud Colas)
* Update Wagtails type scale so StreamField block labels and field labels are the same size (Thibaud Colas)
* Allow customising the `search_fields` and search backend via SnippetViewSet (Sage Abdullah)
* Fix: Ensure `label_format` on StructBlock gracefully handles missing variables (Aadi jindal)
* Fix: Adopt a no-JavaScript and more accessible solution for the 'Reset to default' switch to Gravatar when editing user profile (Loveth Omokaro)
* Fix: Ensure `Site.get_site_root_paths` works on cache backends that do not preserve Python objects (Jaap Roes)

Wyświetl plik

@ -83,6 +83,8 @@ Viewsets are Wagtail's mechanism for defining a group of related admin views wit
.. autoattribute:: list_display
.. autoattribute:: list_filter
.. autoattribute:: filterset_class
.. autoattribute:: search_fields
.. autoattribute:: search_backend_name
.. autoattribute:: list_per_page
.. autoattribute:: ordering
.. autoattribute:: admin_url_namespace

Wyświetl plik

@ -79,6 +79,7 @@ Those improvements were implemented by Albina Starykova as part of an [Outreachy
* Allow overriding the base queryset to be used in snippet `IndexView` (Sage Abdullah)
* Revise alignment and spacing of form fields and sections (Thibaud Colas)
* Update Wagtails type scale so StreamField block labels and field labels are the same size (Thibaud Colas)
* Allow customising the `search_fields` and search backend via SnippetViewSet (Sage Abdullah)
### Bug fixes

Wyświetl plik

@ -83,6 +83,7 @@ class IndexView(
page_kwarg = "p"
default_ordering = None
search_fields = None
search_backend_name = "default"
is_searchable = None
search_kwarg = "q"
filters = None
@ -258,8 +259,8 @@ class IndexView(
if not self.search_query:
return queryset
if class_is_indexed(queryset.model):
search_backend = get_search_backend()
if class_is_indexed(queryset.model) and self.search_backend_name:
search_backend = get_search_backend(self.search_backend_name)
return search_backend.search(
self.search_query, queryset, fields=self.search_fields
)

Wyświetl plik

@ -745,3 +745,71 @@ class TestCustomOrdering(BaseSnippetViewSetTests):
"DDDDDDDDDD",
],
)
class TestDjangoORMSearchBackend(BaseSnippetViewSetTests):
model = DraftStateModel
@classmethod
def setUpTestData(cls):
cls.first = cls.model.objects.create(
text="Wagtail is a Django-based CMS",
)
cls.second = cls.model.objects.create(
text="Django is a Python-based web framework",
)
cls.third = cls.model.objects.create(
text="Python is a programming-bas, uh, language",
)
def get(self, params={}):
return self.client.get(self.get_url("list"), params)
def test_simple(self):
response = self.get()
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "wagtailsnippets/snippets/index.html")
# All objects should be in items
self.assertCountEqual(
list(response.context["page_obj"].object_list),
[self.first, self.second, self.third],
)
# The search box should not raise an error
self.assertNotContains(response, "This field is required.")
def test_empty_q(self):
response = self.get({"q": ""})
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "wagtailsnippets/snippets/index.html")
# All objects should be in items
self.assertCountEqual(
list(response.context["page_obj"].object_list),
[self.first, self.second, self.third],
)
# The search box should not raise an error
self.assertNotContains(response, "This field is required.")
def test_is_searchable(self):
self.assertTrue(self.get().context["is_searchable"])
def test_search_one(self):
response = self.get({"q": "Django"})
# Only objects with "Django" should be in items
self.assertCountEqual(
list(response.context["page_obj"].object_list),
[self.first, self.second],
)
def test_search_the(self):
response = self.get({"q": "Python"})
# Only objects with "Python" should be in items
self.assertCountEqual(
list(response.context["page_obj"].object_list),
[self.second, self.third],
)

Wyświetl plik

@ -647,6 +647,15 @@ class SnippetViewSet(ModelViewSet):
#: The default ordering to use for the index view. Can be a string or a list/tuple in the same format as Django's :attr:`~django.db.models.Options.ordering`.
ordering = None
#: The fields to use for the search in the index view.
#: If set to ``None`` and :attr:`search_backend_name` is set to use a Wagtail search backend,
#: the ``search_fields`` attribute of the model will be used instead.
search_fields = None
#: The name of the Wagtail search backend to use for the search in the index view.
#: If set to a falsy value, the search will fall back to use Django's QuerySet API.
search_backend_name = "default"
#: The URL namespace to use for the admin views.
#: If left unset, ``wagtailsnippets_{app_label}_{model_name}`` is used instead.
admin_url_namespace = None
@ -811,6 +820,8 @@ class SnippetViewSet(ModelViewSet):
list_filter=self.list_filter,
paginate_by=self.list_per_page,
default_ordering=self.ordering,
search_fields=self.search_fields,
search_backend_name=self.search_backend_name,
)
@property
@ -832,6 +843,8 @@ class SnippetViewSet(ModelViewSet):
list_filter=self.list_filter,
paginate_by=self.list_per_page,
default_ordering=self.ordering,
search_fields=self.search_fields,
search_backend_name=self.search_backend_name,
)
@property

Wyświetl plik

@ -250,6 +250,9 @@ class FullFeaturedSnippetViewSet(SnippetViewSet):
index_template_name = "tests/fullfeaturedsnippet_index.html"
ordering = ["text", "-_updated_at", "-pk"]
# TODO: When specific search fields are supported in SQLite FTS (see #10217),
# specify search_fields or get_search_fields here
def get_history_template(self):
return "tests/snippet_history.html"
@ -259,6 +262,8 @@ class FullFeaturedSnippetViewSet(SnippetViewSet):
class DraftStateModelViewSet(SnippetViewSet):
list_filter = ["text", "first_published_at"]
search_fields = ["text"]
search_backend_name = None
class ModeratedModelViewSet(SnippetViewSet):