Problem:
You search by firing POST and paginate by firing GET, so search results disappear on GET. I want to preserve searching results, so user can paginate them.
First I try to use some static class to keep search results, but this solution has bug (thanks to svetlyak). In multiuser environment other user searching got results from previous one. No @cache_control(private=True) helps so I decided to change searching schema by using GET in the first place and to supply query string on each 'paging' request. Also added some memory cache that expires after 5 min
In template
Please append query to each paging link:
<a href="?page={{ page_number }}
&search_query={{ query|urlencode }}">
{{ page_number }}</a>
This snippet should keep search results on pagination in multiuser environment.
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 | search_cache = get_cache('locmem:///')
_CACHE_TIMEOUT = 60*60*5 # 5 min
def search_cacheable(lang, query):
key = urllib.quote(lang + query)
if not search_cache.get(key):
results4blogs = Entry.objects.all()
results4pages = Page.objects.filter(language__exact=lang)
results4photos = Photo.objects.all()
results4comments = Comment.objects.all()
for term in query.split():
results4blogs = results4blogs.filter(Q(headline__icontains=term) | Q(body__icontains=term))
results4pages = results4pages.filter(Q(title__icontains=term) | Q(content__icontains=term))
results4photos = results4photos.filter(Q(title__icontains=term))
results4comments = results4comments.filter(Q(headline__icontains=term) | Q(comment__icontains=term))
rslt = list(set(results4blogs) | set(results4pages) | set(results4photos) | set(results4comments))
search_cache.set(key, rslt, _CACHE_TIMEOUT)
print 'cache created for "%s" in %s' % (query, lang.upper())
else:
rslt = search_cache.get(key)
print 'cache hit for "%s" in %s' % (query, lang.upper())
return rslt
def paginate_results(request):
paginate_by = 5
orphans = 1
lang = request.LANGUAGE_CODE
page = int(request.GET.get('page', '1'))
query = urllib.unquote(request.GET.get('search_query', '')).lower()
results = search_cacheable(lang, query)
paginator = ObjectPaginator(results, paginate_by, orphans)
try:
collection = paginator.get_page(page - 1)
except InvalidPage:
raise Http404
return render_to_response('results.html',
{'results': collection,
'query':query,
'is_paginated': paginator.pages > 1,
'results_per_page': paginate_by,
'has_next': paginator.has_next_page(page - 1),
'has_previous': paginator.has_previous_page(page - 1),
'page': page,
'next': page + 1,
'previous': page - 1,
'pages': paginator.pages,
'hits' : paginator.hits,},
context_instance=RequestContext(request),)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
I made mistake:
You search by firing GET
should say:
You search by firing POST
#
Cool! But how about parallel searches by different users? Seems I get wrong results if someone run search query before I click on Next Page Link :)
#
You are right. Must be something to do with cache control, vary on headers or similar. If you find solution, please post it.
#
This is a bad idea if the search returns a large number of hits, as it will load them all into memory.
#
Please login first before commenting.