Allow search across related fields, optimzed for speed and memory, added LIMIT setting, search elapsed time

This commit is contained in:
Roberto Rosario
2011-03-08 03:35:43 -04:00
parent a116f1807c
commit 5a57a58913
4 changed files with 38 additions and 15 deletions

View File

@@ -1,3 +1,4 @@
from django.conf import settings from django.conf import settings
SHOW_OBJECT_TYPE = getattr(settings, 'SEARCH_SHOW_OBJECT_TYPE', True) SHOW_OBJECT_TYPE = getattr(settings, 'SEARCH_SHOW_OBJECT_TYPE', True)
LIMIT = getattr(settings, 'SEARCH_LIMIT', 100)

View File

@@ -14,5 +14,9 @@
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block footer %}
{% if query_string %}
{% blocktrans %}Elapsed time: {{ time_delta }} seconds{% endblocktrans %}
{% endif %}
{% endblock %}

View File

@@ -1,3 +1,4 @@
import datetime
import re import re
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
@@ -10,7 +11,7 @@ from django.core.exceptions import FieldError
from api import search_list from api import search_list
from forms import SearchForm from forms import SearchForm
from conf.settings import SHOW_OBJECT_TYPE from conf.settings import SHOW_OBJECT_TYPE, LIMIT
#original code from: #original code from:
#http://www.julienphalip.com/blog/2008/08/16/adding-search-django-site-snap/ #http://www.julienphalip.com/blog/2008/08/16/adding-search-django-site-snap/
@@ -34,28 +35,26 @@ def get_query(terms, search_fields):
aims to search keywords within a model by testing the given search fields. aims to search keywords within a model by testing the given search fields.
''' '''
query = None # Query to search for every search term queries = []
#terms = normalize_query(query_string)
for term in terms: for term in terms:
or_query = None # Query to search for a given term in each field or_query = None
for field_name in search_fields: for field_name in search_fields:
q = Q(**{"%s__icontains" % field_name: term}) q = Q(**{'%s__icontains' % field_name:term})
if or_query is None: if or_query is None:
or_query = q or_query = q
else: else:
or_query = or_query | q or_query = or_query | q
if query is None:
query = or_query queries.append(or_query)
else: return queries
query = query & or_query
return query
def search(request): def search(request):
query_string = '' query_string = ''
found_entries = {} found_entries = {}
object_list = [] object_list = []
start_time = datetime.datetime.now()
if ('q' in request.GET) and request.GET['q'].strip(): if ('q' in request.GET) and request.GET['q'].strip():
query_string = request.GET['q'] query_string = request.GET['q']
form = SearchForm(initial={'q':query_string}) form = SearchForm(initial={'q':query_string})
@@ -63,10 +62,20 @@ def search(request):
terms = normalize_query(query_string) terms = normalize_query(query_string)
for model, data in search_list.items(): for model, data in search_list.items():
query = get_query(terms, data['fields']) queries = get_query(terms, data['fields'])
try: try:
results = model.objects.filter(query) model_results = None
for query in queries:
single_results = set(model.objects.filter(query).values_list('pk', flat=True))
#Convert queryset to python set and perform the
#AND operation on the program and not as a query
if model_results == None:
model_results = single_results
else:
model_results &= single_results
results = model.objects.filter(pk__in=model_results)[:LIMIT]
if results: if results:
found_entries[data['text']] = results found_entries[data['text']] = results
for result in results: for result in results:
@@ -78,6 +87,11 @@ def search(request):
else: else:
form = SearchForm() form = SearchForm()
if LIMIT and len(model_results) > LIMIT:
title = _(u'results with: %s (showing only %s out of %s)') % (query_string, LIMIT, len(model_results))
else:
title = _(u'results with: %s') % query_string
context = { context = {
'query_string':query_string, 'query_string':query_string,
'found_entries':found_entries, 'found_entries':found_entries,
@@ -85,7 +99,8 @@ def search(request):
'object_list':object_list, 'object_list':object_list,
'form_title':_(u'Search'), 'form_title':_(u'Search'),
'hide_header':True, 'hide_header':True,
'title':_(u'results with: %s') % query_string 'title':title,
'time_delta':str(datetime.datetime.now() - start_time).split(':')[2]
} }
if SHOW_OBJECT_TYPE: if SHOW_OBJECT_TYPE:

View File

@@ -245,6 +245,9 @@ LOGIN_EXEMPT_URLS = (
# Permissions # Permissions
#ROLES_DEFAULT_ROLES = [] #ROLES_DEFAULT_ROLES = []
# Searching
#SEARCH_LIMIT = 100
# Override # Override
SEARCH_SHOW_OBJECT_TYPE = False SEARCH_SHOW_OBJECT_TYPE = False
#----------- django-celery -------------- #----------- django-celery --------------