Skip to content

Instantly share code, notes, and snippets.

@TimFletcher
Created August 2, 2011 22:31
Show Gist options
  • Save TimFletcher/1121397 to your computer and use it in GitHub Desktop.
Save TimFletcher/1121397 to your computer and use it in GitHub Desktop.
Simple Django Search
import re
from django.db.models import Q
from django.shortcuts import render_to_response
from django.template import RequestContext
from apps.missions.models import Mission
from apps.profiles.models import Profile
def normalize_query(query_string,
findterms=re.compile(r'"([^"]+)"|(\S+)').findall,
normspace=re.compile(r'\s{2,}').sub):
''' Splits the query string in invidual keywords, getting rid of unecessary spaces
and grouping quoted words together.
Example:
>>> normalize_query(' some random words "with quotes " and spaces')
['some', 'random', 'words', 'with quotes', 'and', 'spaces']
'''
return [normspace(' ', (t[0] or t[1]).strip()) for t in findterms(query_string)]
def get_query(query_string, search_fields):
''' Returns a query, that is a combination of Q objects. That combination
aims to search keywords within a model by testing the given search fields.
'''
query = None # Query to search for every search term
terms = normalize_query(query_string)
for term in terms:
or_query = None # Query to search for a given term in each field
for field_name in search_fields:
q = Q(**{"%s__icontains" % field_name: term})
if or_query is None:
or_query = q
else:
or_query = or_query | q
if query is None:
query = or_query
else:
query = query & or_query
return query
def search(request):
# To get around a weird moderator already registered error.
from django.db.models import get_model
Entry = get_model('blog', 'Entry')
query_string = ''
results = {}
params = [{
'name': 'Blog Post',
'manager': Entry.objects.published(),
'fields': ['title', 'body']
},{
'name': 'Mission',
'manager': Mission.objects.published(),
'fields': ['destination', 'description']
},{
'name': 'Profile',
'manager': Profile.objects.active(),
'fields': ['occupation', 'bio', 'user__first_name', 'user__last_name']
}]
if ('q' in request.GET) and request.GET['q'].strip():
query_string = request.GET['q']
for p in params:
entry_query = get_query(query_string, p['fields'])
results[p['name']] = p['manager'].filter(entry_query)
return render_to_response(
'search/search.html', {
'query_string': query_string,
'results': results
},
context_instance=RequestContext(request)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment