# 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): DEFAULT = '' BOOLEAN = ' IN BOOLEAN MODE' NATURAL_LANGUAGE = ' IN NATURAL LANGUAGE MODE' QUERY_EXPANSION = ' WITH QUERY EXPANSION' 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] full_names = ['%s.%s' % (connection.ops.quote_name(meta.db_table), connection.ops.quote_name(column)) for column in columns] # Create the MATCH...AGAINST expressions fulltext_columns = ', '.join(full_names) match_expr = ('MATCH(%s) AGAINST (%%s%s)' % (fulltext_columns, mode)) # Add the extra SELECT and WHERE options return self.extra(select={'relevance': match_expr}, select_params=[query], where=[match_expr], params=[query]) 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)