From a8cf5584204d77bd3f234fe579844ca84bb3558d Mon Sep 17 00:00:00 2001 From: bnewbold Date: Mon, 2 May 2011 21:41:28 -0400 Subject: basic json keyword search --- piccast/feeds/models.py | 39 +++++++++++++++++++++++++++++++++++++++ piccast/feeds/views.py | 22 ++++++++++++++++++++++ piccast/urls.py | 1 + 3 files changed, 62 insertions(+) (limited to 'piccast') diff --git a/piccast/feeds/models.py b/piccast/feeds/models.py index cbc12e4..0ec24f1 100644 --- a/piccast/feeds/models.py +++ b/piccast/feeds/models.py @@ -126,3 +126,42 @@ class PicSet(models.Model): } +# The below search code comes from Julien Phalip + +import re +from django.db.models import Q + +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 + diff --git a/piccast/feeds/views.py b/piccast/feeds/views.py index 1c26d12..d434818 100644 --- a/piccast/feeds/views.py +++ b/piccast/feeds/views.py @@ -35,3 +35,25 @@ def pics_by_set(request, req_picset): pics = Pic.objects.filter(set=req_picset).order_by('id') return HttpResponse(json.dumps({'list':[p.serializable() for p in pics]}, indent=2), mimetype="application/json") +def json_search(request): + query_string = '' + found_feeds = [] + found_picsets = [] + found_pics = [] + query_keywords = [] + if ('q' in request.GET) and request.GET['q'].strip(): + query_string = request.GET['q'] + feed_query = get_query(query_string, ['title', 'description',]) + picset_query = get_query(query_string, ['title', 'description','keywords']) + pic_query = get_query(query_string, ['title', 'description','keywords']) + found_feeds = PicFeed.objects.filter(feed_query).order_by('-created')[:6] + found_picsets = PicSet.objects.filter(picset_query).order_by('-created')[:6] + found_pics = PicSet.objects.filter(pic_query).order_by('-created')[:6] + query_keywords = normalize_query(query_string) + + return HttpResponse(json.dumps({'matching_feeds':[feed.serializable() for feed in found_feeds], + 'matching_picsets':[picset.serializable() for picset in found_picsets], + 'matching_pics':[pic.serializable() for pic in found_pics], + 'query_keywords':query_keywords, + }, indent=2), mimetype="application/json") + diff --git a/piccast/urls.py b/piccast/urls.py index daa67da..51ba2d6 100644 --- a/piccast/urls.py +++ b/piccast/urls.py @@ -23,6 +23,7 @@ urlpatterns = patterns('', (r'^json/pics_by_set/(\d+)/', 'feeds.views.pics_by_set'), (r'^json/sets_by_feed/(\d+)/', 'feeds.views.sets_by_feed'), (r'^json/sets_by_feed/([-\w]+)/', 'feeds.views.sets_by_feedslug'), + (r'^json/search', 'feeds.views.json_search'), (r'^$', 'feeds.views.basic_frontpage'), ) -- cgit v1.2.3