This app allows you to utilize mysql's fulltext searching over multiple models and multiple apps, letting the site search seem more intuitive, yet still allow your content to be very structured. Essentially, it creates an entire new model that associates objects to a chunk of text to search efficiently over (and index), using the contenttypes app. Simply add the post_save events to your existing models for things you want to be searched.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | ##################
# 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 %}
<div id="searchresults">
{% for o in results %}
<div class="searchresult">
{% ifequal o.content_type.name "video" %}
{% with o.content_object as video %}
<!-- Video search result here -->
{% endwith %}
{% endifequal %}
{% ifequal o.content_type.name "blogentry" %}
{% with o.content_object as blogentry %}
<!-- BlogEntry search result here -->
{% endwith %}
{% endifequal %}
</div>
{% endfor %}
</div>
{% endblock %}
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Please login first before commenting.