search.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. from django.utils.translation import ugettext_lazy as _
  2. class SearchException(Exception):
  3. pass
  4. class SearchQuery(object):
  5. def __init__(self, raw_query=None):
  6. """
  7. Build search query object
  8. """
  9. if raw_query:
  10. self.parse_query(raw_query)
  11. def parse_query(self, raw_query):
  12. """
  13. Parse raw search query into dict of lists of words that should be found and cant be found in string
  14. """
  15. self.criteria = {'+': [], '-': []}
  16. for word in unicode(raw_query).split():
  17. # Trim word and skip it if its empty
  18. word = unicode(word).strip().lower()
  19. if len(word) == 0:
  20. pass
  21. # Find word mode
  22. mode = '+'
  23. if word[0] == '-':
  24. mode = '-'
  25. word = unicode(word[1:]).strip()
  26. # Strip extra crap
  27. word = ''.join(e for e in word if e.isalnum())
  28. # Slice word?
  29. if len(word) <= 3:
  30. raise SearchException(_("One or more search phrases are shorter than four characters."))
  31. if mode == '+':
  32. if len(word) == 5:
  33. word = word[0:-1]
  34. if len(word) == 6:
  35. word = word[0:-2]
  36. if len(word) > 6:
  37. word = word[0:-3]
  38. self.criteria[mode].append(word)
  39. # Complain that there are no positive matches
  40. if not self.criteria['+'] and not self.criteria['-']:
  41. raise SearchException(_("Search query is invalid."))
  42. def search(self, value):
  43. """
  44. See if value meets search criteria, return True for success and False otherwhise
  45. """
  46. try:
  47. value = unicode(value).strip().lower()
  48. # Search for only
  49. if self.criteria['+'] and not self.criteria['-']:
  50. return self.search_for(value)
  51. # Search against only
  52. if self.criteria['-'] and not self.criteria['+']:
  53. return self.search_against(value)
  54. # Search if contains for values but not against values
  55. return self.search_for(value) and not self.search_against(value)
  56. except AttributeError:
  57. raise SearchException(_("You have to define search query before you will be able to search."))
  58. def search_for(self, value):
  59. """
  60. See if value is required
  61. """
  62. for word in self.criteria['+']:
  63. if value.find(word) != -1:
  64. return True
  65. return False
  66. def search_against(self, value):
  67. """
  68. See if value is forbidden
  69. """
  70. for word in self.criteria['-']:
  71. if value.find(word) != -1:
  72. return True
  73. return False