kpsul/shared/views/autocomplete.py

58 lines
1.8 KiB
Python
Raw Normal View History

from dal import autocomplete
from django.db.models import Q
2020-01-02 16:01:13 +01:00
class ModelSearch:
2020-01-02 16:01:13 +01:00
"""Basic search engine for models based on filtering.
The class should be configured through its ``model`` class attribute: the ``search``
method will return a queryset of instances of this model. The ``search_fields``
attributes indicates which fields to search in.
2020-01-03 17:26:12 +01:00
Example:
>>> from django.contrib.auth.models import User
>>>
>>> class UserSearch(ModelSearch):
... model = User
... search_fields = ["username", "first_name", "last_name"]
>>>
>>> user_search = UserSearch() # has type ModelSearch[User]
>>> user_search.search(["toto", "foo"]) # returns a queryset of Users
2020-01-02 16:01:13 +01:00
"""
model = None
search_fields = []
2020-01-02 16:01:13 +01:00
def get_queryset_filter(self, keywords):
2020-01-02 16:01:13 +01:00
filter_q = Q()
if not keywords:
return filter_q
for keyword in keywords:
kw_filter = Q()
for field in self.search_fields:
kw_filter |= Q(**{"{}__icontains".format(field): keyword})
filter_q &= kw_filter
return filter_q
def search(self, keywords):
2020-01-02 16:01:13 +01:00
"""Returns the queryset of model instances matching all the keywords.
The semantic of the search is the following: a model instance appears in the
search results iff all of the keywords given as arguments occur in at least one
of the search fields.
"""
return self.model.objects.filter(self.get_queryset_filter(keywords))
class Select2QuerySetView(ModelSearch, autocomplete.Select2QuerySetView):
"""Compatibility layer between ModelSearch and Select2QuerySetView."""
def get_queryset(self):
keywords = self.q.split()
return super().search(keywords)