################## # models.py ################## from search import SearchQuerySet from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic # Make sure to create this fulltext index! # create fulltext index searchable_media on searchable_searchablemedia (search_text); # class SearchableMediaManager(models.Manager): def search(self,query): return SearchQuerySet(self.model,['search_text']).search(query) class SearchableMedia(models.Model): objects=SearchableMediaManager() content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type','object_id') search_text = models.TextField() def __str__(self): return "Searchable Content for %s-%s"%(self.content_type.name,self.get_content_object()) def get_content_object(self): return self.content_object # for debug for now class Admin: pass def update_terms(object,terms): sm=None try: sm=SearchableMedia.objects.get(content_type=ContentType.objects.get_for_model(object),object_id=object.id) except SearchableMedia.DoesNotExist: sm=SearchableMedia(content_type=ContentType.objects.get_for_model(object),object_id=object.id) if sm: sm.search_text=terms sm.save() ################## # views.py ################## from django.http import HttpResponseRedirect from django.shortcuts import render_to_response from django.template import RequestContext from models import SearchableMedia # Create your views here. def search(request,template="search.html"): if "keyword" not in request.REQUEST: return HttpResponseRedirect("/") results=SearchableMedia.objects.search(request.REQUEST["keyword"]) return render_to_response(template,{"results":results},context_instance=RequestContext(request)) ################## # search.py ################## from django.db import models, backend class SearchQuerySet(models.query.QuerySet): """ Search Query Set courtesy of http://www.mercurytide.com/whitepapers/django-full-text-search/ """ def __init__(self, model=None, fields=None): super(SearchQuerySet, self).__init__(model) self._search_fields = fields def search(self, query): meta = self.model._meta db_operations = backend.DatabaseOperations() # Get the table name and column names from the model # in `table_name`.`column_name` style columns = [meta.get_field(name, many_to_many=False).column for name in self._search_fields] full_names = ["%s.%s" % (db_operations.quote_name(meta.db_table), db_operations.quote_name(column)) for column in columns] # Create the MATCH AGAINST expressions fulltext_columns = ", ".join(full_names) match_expr = ("MATCH(%s) AGAINST (%%s)" % fulltext_columns) # Add the extra SELECT and WHERE options return self.extra(select={'relevance': match_expr}, where=[match_expr], params=[query, query]) ################## # models.py of objects you want included in search ################## def post_blogentry_save(sender,instance): update_terms(instance," ".join([instance.title,instance.body])) dispatcher.connect(post_blogentry_save, sender=BlogEntry, signal=models.signals.post_save) def post_video_save(sender,instance): update_terms(instance," ".join([instance.title,instance.body])) dispatcher.connect(post_video_save, sender=Video, signal=models.signals.post_save) ################## # Template ################## {% extends "base.html" %} {% block content %}
{% for o in results %}
{% ifequal o.content_type.name "video" %} {% with o.content_object as video %} {% endwith %} {% endifequal %} {% ifequal o.content_type.name "blogentry" %} {% with o.content_object as blogentry %} {% endwith %} {% endifequal %}
{% endfor %}
{% endblock %}