Created
August 2, 2011 22:31
-
-
Save TimFletcher/1121397 to your computer and use it in GitHub Desktop.
Simple Django Search
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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