Simple search in Django
If you want a really simple search you can use icontains
lookup and Q
object:
from django.db.models import Q
results = BlogPost.objects.filter(Q(title__icontains=your_search_query) | Q(intro__icontains=your_search_query) | Q(content__icontains=your_search_query))
You should also note that Haystack doesn't have to be "hideously complicated". You can set up haystack with Whoosh backend in less then 15 minutes.
Update 2016: In version 1.10 Django added a full text search support (PostgreSQL only). An answer to the original question using the new module might look something like this:
from django.contrib.postgres.search import SearchVector
results = BlogPost.objects.annotate(
search=SearchVector('title', 'intro', 'content'),
).filter(search=your_search_query)
The new full text search module contains a lot more features (for example sorting by relevancy), you can read about them in the documentation.
From the Django source:
# Apply keyword searches.
def construct_search(field_name):
if field_name.startswith('^'):
return "%s__istartswith" % field_name[1:]
elif field_name.startswith('='):
return "%s__iexact" % field_name[1:]
elif field_name.startswith('@'):
return "%s__search" % field_name[1:]
else:
return "%s__icontains" % field_name
if self.search_fields and self.query:
for bit in self.query.split():
or_queries = [models.Q(**{construct_search(str(field_name)): bit}) for field_name in self.search_fields]
qs = qs.filter(reduce(operator.or_, or_queries))
for field_name in self.search_fields:
if '__' in field_name:
qs = qs.distinct()
break
Clearly, it uses the database options to perform search. If nothing else, you should be able to reuse some of the code from it.
So says the documentation too: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields
The full text search, however, uses the MySQL index (only if you are using MySQL).
You would use the __search operator. It's documented in the Django QuerySet API Reference. There's also istartswith, which does a case-insensitive starts-with search.
Here's a working example (adapted from my own Django site):
def search(request):
try:
q = request.GET['q']
posts = BlogPost.objects.filter(title__search=q) | \
BlogPost.objects.filter(intro__search=q) | \
BlogPost.objects.filter(content__search=q)
return render_to_response('search/results.html', {'posts':posts, 'q':q})
except KeyError:
return render_to_response('search/results.html')
Note that __search is only available in MySQL and requires direct manipulation of the database to add the full-text index. See the MySQL documentation for additional details.