Simple search in Django
If you want a really simple search you can use icontains
lookup and Q
object:
from django.db.models import Qresults = 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 SearchVectorresults = 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_nameif 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.