diff --git a/wagtail/contrib/postgres_search/backend.py b/wagtail/contrib/postgres_search/backend.py index d4bdfa832c..ac32d2ae62 100644 --- a/wagtail/contrib/postgres_search/backend.py +++ b/wagtail/contrib/postgres_search/backend.py @@ -55,6 +55,7 @@ class ObjectIndexer: self.prepare_value(field.get_value(obj))) elif isinstance(field, AutocompleteField): + # AutocompleteField does not define a boost parameter, so use a base weight of 'D' yield (field, 'D', self.prepare_value(field.get_value(obj))) elif isinstance(field, RelatedFields): @@ -255,26 +256,34 @@ class Index: class PostgresSearchQueryCompiler(BaseSearchQueryCompiler): DEFAULT_OPERATOR = 'and' LAST_TERM_IS_PREFIX = False + TARGET_SEARCH_FIELD_TYPE = SearchField def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.search_fields = self.queryset.model.get_searchable_search_fields() + local_search_fields = self.get_search_fields_for_model() # Due to a Django bug, arrays are not automatically converted # when we use WEIGHTS_VALUES. self.sql_weights = get_sql_weights() - if self.fields is not None: - search_fields = self.queryset.model.get_searchable_search_fields() + if self.fields is None: + # search over the fields defined on the current model + self.search_fields = local_search_fields + else: + # build a search_fields set from the passed definition, + # which may involve traversing relations self.search_fields = { - field_lookup: self.get_search_field(field_lookup, fields=search_fields) + field_lookup: self.get_search_field(field_lookup, fields=local_search_fields) for field_lookup in self.fields } def get_config(self, backend): return backend.config + def get_search_fields_for_model(self): + return self.queryset.model.get_searchable_search_fields() + def get_search_field(self, field_lookup, fields=None): if fields is None: fields = self.search_fields @@ -285,7 +294,7 @@ class PostgresSearchQueryCompiler(BaseSearchQueryCompiler): sub_field_name = None for field in fields: - if isinstance(field, SearchField) and field.field_name == field_lookup: + if isinstance(field, self.TARGET_SEARCH_FIELD_TYPE) and field.field_name == field_lookup: return field # Note: Searching on a specific related field using @@ -465,10 +474,14 @@ class PostgresSearchQueryCompiler(BaseSearchQueryCompiler): class PostgresAutocompleteQueryCompiler(PostgresSearchQueryCompiler): LAST_TERM_IS_PREFIX = True + TARGET_SEARCH_FIELD_TYPE = AutocompleteField def get_config(self, backend): return backend.autocomplete_config + def get_search_fields_for_model(self): + return self.queryset.model.get_autocomplete_search_fields() + def get_index_vector(self, search_query): return F('index_entries__autocomplete') @@ -477,10 +490,9 @@ class PostgresAutocompleteQueryCompiler(PostgresSearchQueryCompiler): SearchVector( field_lookup, config=search_query.config, - weight=get_weight(search_field.boost) + weight='D', ) for field_lookup, search_field in self.search_fields.items() - if search_field.partial_match ) diff --git a/wagtail/search/tests/test_backends.py b/wagtail/search/tests/test_backends.py index 2102e3983e..52716fa31e 100644 --- a/wagtail/search/tests/test_backends.py +++ b/wagtail/search/tests/test_backends.py @@ -187,6 +187,18 @@ class BackendTests(WagtailTestUtils): "Learning Python", ]) + # Autocomplete should only require an AutocompleteField, not a SearchField with + # partial_match=True + results = self.backend.autocomplete("Georg", models.Author) + self.assertUnsortedListEqual([r.name for r in results], [ + "George R.R. Martin", + ]) + + results = self.backend.autocomplete("Georg", models.Author, fields=['name']) + self.assertUnsortedListEqual([r.name for r in results], [ + "George R.R. Martin", + ]) + def test_autocomplete_not_affected_by_stemming(self): # If SEARCH_CONFIG is set, stemming will be enabled. # But we want to disable this for autocomplete as stemmed words don't always match on prefixes diff --git a/wagtail/tests/search/models.py b/wagtail/tests/search/models.py index 085c65aceb..407e9c3f8b 100644 --- a/wagtail/tests/search/models.py +++ b/wagtail/tests/search/models.py @@ -10,6 +10,7 @@ class Author(index.Indexed, models.Model): search_fields = [ index.SearchField('name'), + index.AutocompleteField('name'), index.FilterField('date_of_birth'), ]