Skip to content

Instantly share code, notes, and snippets.

@augustomen
Last active December 11, 2015 02:39
Show Gist options
  • Save augustomen/4532518 to your computer and use it in GitHub Desktop.
Save augustomen/4532518 to your computer and use it in GitHub Desktop.
WordModelLookup: a Django Selectable lookup that searches anywhere in the field
import operator
from django.db.models import Q
from selectable.base import LookupBase, ModelLookup
# if term is 'foo - bar', the middle '-' is ignored
SEARCH_IGNORED = (',', '.', '-', '/', ';', ':', '=', '\\',)
def split_terms(get_query):
""" This decorator breaks a single string received in the request by a
list of strings.
This is used to search an expression in any order. Example:
User input: ?term="foo bar"
Without the decorator, searches by exactly "foo bar"
With the decorator, term=["foo", "bar"]
"""
def wrapper(self, request, term):
terms = [s for s in term.split() if s and s not in SEARCH_IGNORED]
return get_query(self, request, terms)
return wrapper
class WordModelLookup(ModelLookup):
""" Same as ModelLookup, but searches string part instead of whole.
Example:
term: "foo bar"
output query:
SELECT * FROM model WHERE
[search_field] like "%foo%" AND
[search_field] like "%bar%"
search_field should contain __icontains, __istartswith or
__iendswith, otherwise it won't make much sense.
"""
@split_terms
def get_query(self, request, terms):
qs = self.get_queryset()
for term in terms:
search_filters = []
for field in self.search_fields:
search_filters.append(Q(**{field: term}))
qs = qs.filter(reduce(operator.or_, search_filters))
return qs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment