2020-01-21 06:35:58 +00:00
|
|
|
# From: http://www.mercurytide.co.uk/news/article/django-full-text-search/
|
|
|
|
|
|
|
|
from django.db import connection, models
|
|
|
|
from django.db.models.query import QuerySet
|
|
|
|
|
|
|
|
|
|
|
|
class SearchQuerySet(QuerySet):
|
2022-05-14 17:57:27 +00:00
|
|
|
DEFAULT = ""
|
|
|
|
BOOLEAN = " IN BOOLEAN MODE"
|
|
|
|
NATURAL_LANGUAGE = " IN NATURAL LANGUAGE MODE"
|
|
|
|
QUERY_EXPANSION = " WITH QUERY EXPANSION"
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
def __init__(self, fields=None, **kwargs):
|
|
|
|
super(SearchQuerySet, self).__init__(**kwargs)
|
|
|
|
self._search_fields = fields
|
|
|
|
|
|
|
|
def _clone(self, *args, **kwargs):
|
|
|
|
queryset = super(SearchQuerySet, self)._clone(*args, **kwargs)
|
|
|
|
queryset._search_fields = self._search_fields
|
|
|
|
return queryset
|
|
|
|
|
|
|
|
def search(self, query, mode=DEFAULT):
|
|
|
|
meta = self.model._meta
|
|
|
|
|
|
|
|
# Get the table name and column names from the model
|
|
|
|
# in `table_name`.`column_name` style
|
|
|
|
columns = [meta.get_field(name).column for name in self._search_fields]
|
2022-05-14 17:57:27 +00:00
|
|
|
full_names = [
|
|
|
|
"%s.%s"
|
|
|
|
% (
|
|
|
|
connection.ops.quote_name(meta.db_table),
|
|
|
|
connection.ops.quote_name(column),
|
|
|
|
)
|
|
|
|
for column in columns
|
|
|
|
]
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
# Create the MATCH...AGAINST expressions
|
2022-05-14 17:57:27 +00:00
|
|
|
fulltext_columns = ", ".join(full_names)
|
|
|
|
match_expr = "MATCH(%s) AGAINST (%%s%s)" % (fulltext_columns, mode)
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
# Add the extra SELECT and WHERE options
|
2022-05-14 17:57:27 +00:00
|
|
|
return self.extra(
|
|
|
|
select={"relevance": match_expr},
|
|
|
|
select_params=[query],
|
|
|
|
where=[match_expr],
|
|
|
|
params=[query],
|
|
|
|
)
|
2020-01-21 06:35:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
class SearchManager(models.Manager):
|
|
|
|
def __init__(self, fields=None):
|
|
|
|
super(SearchManager, self).__init__()
|
|
|
|
self._search_fields = fields
|
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
if self._search_fields is not None:
|
|
|
|
return SearchQuerySet(model=self.model, fields=self._search_fields)
|
|
|
|
return super(SearchManager, self).get_queryset()
|
|
|
|
|
|
|
|
def search(self, *args, **kwargs):
|
|
|
|
return self.get_queryset().search(*args, **kwargs)
|