-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
- Tested with the latest Haystack release
- Tested with the current Haystack master branch
Expected behaviour
Passing to the haystack search engine string with spaces should create a query to the db using all of the specified words, combining everything into a single WHERE clause. The returned result should be all records that contain all those specified words.
Actual behaviour
Haystack creates query using only the last given word in the string. Escaping spaces or using python urllib.parse.quote()
function doesn't change anything.
Example:
Model Category:
class Category(model.Model):
name = models.CharField(_("Name"), max_length=255, db_index=True)
description = models.TextField(_("Description"), blank=True)
image = models.ImageField(_("Image"), upload_to="categories", blank=True, null=True, max_length=255)
slug = SlugField(_("Slug"), max_length=255, db_index=True)
path = models.CharField(_("Path"), max_length=255)
The WHERE clause in the query created based on the request response = api_client.get(f"{url}?q=word1 word2 word3")
should look like this:
WHERE ((UPPER("catalogue_category"."path"::text) LIKE UPPER(\'%word1%\')
OR UPPER("catalogue_category"."name"::text) LIKE UPPER(\'%word1%\')
OR UPPER("catalogue_category"."description"::text) LIKE UPPER(\'%word1%\')
OR UPPER("catalogue_category"."slug"::text) LIKE UPPER(\'%word1%\'))
AND
(UPPER("catalogue_category"."path"::text) LIKE UPPER(\'%word2%\')
OR UPPER("catalogue_category"."name"::text) LIKE UPPER(\'%word2%\')
OR UPPER("catalogue_category"."description"::text) LIKE UPPER(\'%word2%\')
OR UPPER("catalogue_category"."slug"::text) LIKE UPPER(\'%word2%\'))
AND
(UPPER("catalogue_category"."path"::text) LIKE UPPER(\'%word3%\')
OR UPPER("catalogue_category"."name"::text) LIKE UPPER(\'%word3%\')
OR UPPER("catalogue_category"."description"::text) LIKE UPPER(\'%word3%\')
OR UPPER("catalogue_category"."slug"::text) LIKE UPPER(\'%word3%\')))`
but it actually look like this:
WHERE (UPPER("catalogue_category"."path"::text) LIKE UPPER(\'%word3%\')
OR UPPER("catalogue_category"."name"::text) LIKE UPPER(\'%word3%\')
OR UPPER("catalogue_category"."description"::text) LIKE UPPER(\'%word3%\')
OR UPPER("catalogue_category"."slug"::text) LIKE UPPER(\'%word3%\'))
Steps to reproduce the behaviour
-
Set a class using the SearchQuerySet from haystack to filter objects from db. Example of use:
def filter_queryset( self, request: Request, queryset: "QuerySet[Model]", view: GenericViewSet ) -> "QuerySet[Model]": sqs = SearchQuerySet().models(queryset.model) # Get search parameters param = request.query_params.get(self.search_param_name) if not param: return queryset results = [i.object.pk for i in sqs.filter(content=param)] # Return results as a QuerySet return queryset.filter(id__in=results)
-
Set the backend of SimpleSearchBackend:
HAYSTACK_CONNECTIONS = {"default": {"ENGINE": "haystack.backends.simple_backend.SimpleEngine"}}
-
Use this to filter objects by a string containing more than one word separated by spaces (string can be quoted).
-
Check the created SQL query or results, trying to get objects that match not only the last word but all the specified words. Instead of filtering out objects that do not contain all of the specified words, the query will only filter out objects that do not contain the last word in the string.
Configuration
- Operating system version: macOS Big Sur v11.6
- Search engine version: n/a
- Python version: 3.8.12
- Django version: 3.2.2
- Haystack version: 3.1.0