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

Modeladmin search backend #5208

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions wagtail/contrib/modeladmin/helpers/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .button import ButtonHelper, PageButtonHelper # NOQA
from .permission import PagePermissionHelper, PermissionHelper # NOQA
from .url import AdminURLHelper, PageAdminURLHelper # NOQA
from .button import ButtonHelper, PageButtonHelper # NOQA
from .permission import PagePermissionHelper, PermissionHelper # NOQA
from .search import DjangoORMSearchHandler, WagtailBackendSearchHandler # NOQA
from .url import AdminURLHelper, PageAdminURLHelper # NOQA
49 changes: 49 additions & 0 deletions wagtail/contrib/modeladmin/helpers/search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import operator
from functools import reduce

from django.contrib.admin.utils import lookup_needs_distinct
from django.db.models import Q

from wagtail.search.backends import get_search_backend


class ModelAdminSearchHandler:
seb-b marked this conversation as resolved.
Show resolved Hide resolved
def __init__(self, queryset, search_fields):
self.queryset = queryset
self.search_fields = search_fields

def search(self, search_term):
"""
Returns a tuple containing a queryset to implement the search,
and a boolean indicating if the results may contain duplicates.
"""
raise NotImplementedError()

ababic marked this conversation as resolved.
Show resolved Hide resolved

class DjangoORMSearchHandler(ModelAdminSearchHandler):
def search(self, search_term):
if not search_term or self.search_fields:
return self.queryset
use_distinct = False
querset = self.queryset
orm_lookups = ['%s__icontains' % str(search_field)
for search_field in self.search_fields]
for bit in search_term.split():
or_queries = [Q(**{orm_lookup: bit})
for orm_lookup in orm_lookups]
querset = querset.filter(reduce(operator.or_, or_queries))
opts = querset.model._meta
for search_spec in orm_lookups:
# Check wether out results may have duplicates, then remove them
if lookup_needs_distinct(opts, search_spec):
use_distinct = True
break
return querset, use_distinct


class WagtailBackendSearchHandler(ModelAdminSearchHandler):
def search(self, search_term):
backend = get_search_backend()
if self.search_fields:
return backend.search(search_term, self.queryset, fields=self.search_fields), False
return backend.search(search_term, self.queryset), False
5 changes: 3 additions & 2 deletions wagtail/contrib/modeladmin/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
from wagtail.core.models import Page

from .helpers import (
AdminURLHelper, ButtonHelper, PageAdminURLHelper, PageButtonHelper, PagePermissionHelper,
PermissionHelper)
AdminURLHelper, ButtonHelper, DjangoORMSearchHandler, PageAdminURLHelper, PageButtonHelper,
PagePermissionHelper, PermissionHelper)
from .menus import GroupMenuItem, ModelAdminMenuItem, SubMenu
from .mixins import ThumbnailMixin # NOQA
from .views import ChooseParentView, CreateView, DeleteView, EditView, IndexView, InspectView
Expand Down Expand Up @@ -96,6 +96,7 @@ class ModelAdmin(WagtailRegisterable):
inspect_template_name = ''
delete_template_name = ''
choose_parent_template_name = ''
search_handler_class = DjangoORMSearchHandler
permission_helper_class = None
url_helper_class = None
button_helper_class = None
Expand Down
29 changes: 3 additions & 26 deletions wagtail/contrib/modeladmin/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ def dispatch(self, request, *args, **kwargs):
self.search_fields = self.model_admin.get_search_fields(request)
self.items_per_page = self.model_admin.list_per_page
self.select_related = self.model_admin.list_select_related
self.search_handler_class = self.model_admin.search_handler_class

# Get search parameters from the query string.
try:
Expand Down Expand Up @@ -271,32 +272,8 @@ def get_buttons_for_obj(self, obj):
obj, classnames_add=['button-small', 'button-secondary'])

def get_search_results(self, request, queryset, search_term):
"""
Returns a tuple containing a queryset to implement the search,
and a boolean indicating if the results may contain duplicates.
"""
use_distinct = False
if search_term:
if issubclass(self.model, Indexed):
backend = get_search_backend()
if self.search_fields:
queryset = backend.search(search_term, queryset, fields=self.search_fields)
else:
queryset = backend.search(search_term, queryset)
elif self.search_fields:
orm_lookups = ['%s__icontains' % str(search_field)
for search_field in self.search_fields]
for bit in search_term.split():
or_queries = [models.Q(**{orm_lookup: bit})
for orm_lookup in orm_lookups]
queryset = queryset.filter(reduce(operator.or_, or_queries))
if not use_distinct:
for search_spec in orm_lookups:
if lookup_needs_distinct(self.opts, search_spec):
use_distinct = True
break

return queryset, use_distinct
SearchHandler = self.search_handler_class(queryset, self.search_fields)
return SearchHandler.search(search_term)

def lookup_allowed(self, lookup, value):
# Check FKey lookups that are allowed, so that popups produced by
Expand Down