__init__.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. # Backend loading
  2. # Based on the Django cache framework
  3. # https://github.com/django/django/blob/5d263dee304fdaf95e18d2f0619d6925984a7f02/django/core/cache/__init__.py
  4. from importlib import import_module
  5. from django.conf import settings
  6. from django.core.exceptions import ImproperlyConfigured
  7. from django.utils.module_loading import import_string
  8. class InvalidSearchBackendError(ImproperlyConfigured):
  9. pass
  10. def get_search_backend_config():
  11. search_backends = getattr(settings, 'WAGTAILSEARCH_BACKENDS', {})
  12. # Make sure the default backend is always defined
  13. search_backends.setdefault('default', {
  14. 'BACKEND': 'wagtail.search.backends.db',
  15. })
  16. return search_backends
  17. def import_backend(dotted_path):
  18. """
  19. There's two formats for the dotted_path.
  20. One with the backend class (old) and one without (new)
  21. eg:
  22. old: wagtail.search.backends.elasticsearch.ElasticsearchSearchBackend
  23. new: wagtail.search.backends.elasticsearch
  24. If a new style dotted path was specified, this function would
  25. look for a backend class from the "SearchBackend" attribute.
  26. """
  27. try:
  28. # New
  29. backend_module = import_module(dotted_path)
  30. return backend_module.SearchBackend
  31. except ImportError as e:
  32. try:
  33. # Old
  34. return import_string(dotted_path)
  35. except ImportError:
  36. raise ImportError from e
  37. def get_search_backend(backend='default', **kwargs):
  38. search_backends = get_search_backend_config()
  39. # Try to find the backend
  40. try:
  41. # Try to get the WAGTAILSEARCH_BACKENDS entry for the given backend name first
  42. conf = search_backends[backend]
  43. except KeyError:
  44. try:
  45. # Trying to import the given backend, in case it's a dotted path
  46. import_backend(backend)
  47. except ImportError as e:
  48. raise InvalidSearchBackendError("Could not find backend '%s': %s" % (
  49. backend, e))
  50. params = kwargs
  51. else:
  52. # Backend is a conf entry
  53. params = conf.copy()
  54. params.update(kwargs)
  55. backend = params.pop('BACKEND')
  56. # Try to import the backend
  57. try:
  58. backend_cls = import_backend(backend)
  59. except ImportError as e:
  60. raise InvalidSearchBackendError("Could not find backend '%s': %s" % (
  61. backend, e))
  62. # Create backend
  63. return backend_cls(params)
  64. def _backend_requires_auto_update(backend_name, params):
  65. if params.get('AUTO_UPDATE', True):
  66. return True
  67. # _WAGTAILSEARCH_FORCE_AUTO_UPDATE is only used by Wagtail tests. It allows
  68. # us to test AUTO_UPDATE behaviour against Elasticsearch without having to
  69. # have AUTO_UPDATE enabed for every test.
  70. force_auto_update = getattr(settings, '_WAGTAILSEARCH_FORCE_AUTO_UPDATE', [])
  71. if backend_name in force_auto_update:
  72. return True
  73. return False
  74. def get_search_backends_with_name(with_auto_update=False):
  75. search_backends = get_search_backend_config()
  76. for backend, params in search_backends.items():
  77. if with_auto_update and _backend_requires_auto_update(backend, params) is False:
  78. continue
  79. yield backend, get_search_backend(backend)
  80. def get_search_backends(with_auto_update=False):
  81. # For backwards compatibility
  82. return (backend for _, backend in get_search_backends_with_name(with_auto_update=with_auto_update))