search.py 3.1 KB

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