Postgres-backed partial search functionality in Wagtail

Feedback


Solution 1:

The Wagtail search API is being reconstructed to ensure that autocomplete functions consistently across all backends.

At present, the search data can be accessed through the

IndexEntry

model. However, there is no built-in capability for an autocomplete query in

django.contrib.postgres.search

, so we need to perform this task manually. Here are the steps to follow for achieving this.

from django.contrib.postgres.search import SearchQuery
from wagtail.contrib.postgres_search.models import IndexEntry
class SearchAutocomplete(SearchQuery):
    def as_sql(self, compiler, connection):
        return "to_tsquery(''%s':*')", [self.value]
query = SearchAutocomplete('postg')
print(IndexEntry.objects.filter(body_search=query).rank(query))
# All results containing words starting with “postg”
# should be displayed, sorted by relevance.


Solution 2:


Although it lacks documentation, the essence of utilizing a request object for autocomplete filtering with Postgres seems to be present.

from django.conf import settings
from wagtail.search.backends import get_search_backend
from wagtail.search.backends.base import FilterFieldError, OrderByFieldError
def filter_queryset(queryset, request):
    search_query = request.GET.get("search", "").strip()
    search_enabled = getattr(settings, 'WAGTAILAPI_SEARCH_ENABLED', True)
    if 'search' in request.GET and search_query:
        if not search_enabled:
            raise BadRequestError("search is disabled")
        search_operator = request.GET.get('search_operator', None)
        order_by_relevance = 'order' not in request.GET
        sb = get_search_backend()
        try:
            queryset = sb.autocomplete(search_query, queryset, operator=search_operator, order_by_relevance=order_by_relevance)
        except FilterFieldError as e:
            raise BadRequestError("cannot filter by '{}' while searching (field is not indexed)".format(e.field_name))
        except OrderByFieldError as e:
            raise BadRequestError("cannot order by '{}' while searching (field is not indexed)".format(e.field_name))

The significant instruction is to make use of the code labeled as

sb.autocomplete

.

In order to utilize custom fields with autocomplete, it is necessary to include them in

search_fields

as both an

AutocompleteField

and

SearchField

. This can be illustrated with an example.

search_fields = Page.search_fields + [
    index.SearchField("field_to_index", partial_match=True)
    index.AutocompleteField("field_to_index", partial_match=True),
    ...

If you are using Wagtail 2.3, this solution will work. However, it is not guaranteed to work with older versions and there is no guarantee that it will be included in future official documents. Previous documents stated that autocomplete with Postgres was impossible, but thanks to the efforts of Bertrand Bordage, this has been proven untrue.

Frequently Asked Questions