search.py 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
  2. from django.utils.translation import ugettext_lazy as _
  3. from misago.conf import settings
  4. from misago.core.shortcuts import paginate, pagination_dict
  5. from misago.search import SearchProvider
  6. from .models import Post, Thread
  7. from .permissions import exclude_invisible_threads
  8. from .serializers import FeedSerializer
  9. from .utils import add_categories_to_items
  10. from .viewmodels import ThreadsRootCategory
  11. class SearchThreads(SearchProvider):
  12. name = _("Threads")
  13. url = 'threads'
  14. def search(self, query, page=1):
  15. root_category = ThreadsRootCategory(self.request)
  16. threads_categories = [root_category.unwrap()] + root_category.subcategories
  17. if len(query) > 2:
  18. visible_threads = exclude_invisible_threads(
  19. self.request.user, threads_categories, Thread.objects
  20. )
  21. results = search_threads(self.request, query, visible_threads)
  22. else:
  23. results = []
  24. list_page = paginate(
  25. results,
  26. page,
  27. settings.MISAGO_POSTS_PER_PAGE,
  28. settings.MISAGO_POSTS_TAIL,
  29. allow_explicit_first_page=True
  30. )
  31. paginator = pagination_dict(list_page)
  32. posts = list(list_page.object_list)
  33. threads = []
  34. for post in posts:
  35. threads.append(post.thread)
  36. add_categories_to_items(root_category.unwrap(), threads_categories, posts + threads)
  37. results = {
  38. 'results': FeedSerializer(posts, many=True, context={'user': self.request.user}).data
  39. }
  40. results.update(paginator)
  41. return results
  42. def search_threads(request, query, visible_threads):
  43. search_query = SearchQuery(query, config=settings.MISAGO_SEARCH_CONFIG)
  44. search_vector = SearchVector('search_document', config=settings.MISAGO_SEARCH_CONFIG)
  45. return Post.objects.select_related('thread', 'poster').filter(
  46. is_event=False,
  47. is_hidden=False,
  48. is_unapproved=False,
  49. thread_id__in=visible_threads.values('id'),
  50. search_vector=search_query
  51. ).annotate(rank=SearchRank(search_vector, search_query)).order_by('-rank', '-id')