Clean up search backend class

This commit is contained in:
jeremystretch 2022-10-10 13:46:38 -04:00
parent 3750659c37
commit 325f4f1aa1
2 changed files with 26 additions and 40 deletions

View File

@ -17,28 +17,10 @@ class SearchEngineError(Exception):
pass pass
class SearchBackend(object): class SearchBackend:
"""A search engine capable of performing multi-table searches.""" """A search engine capable of performing multi-table searches."""
_created_engines: dict = dict()
_search_choice_options = tuple() _search_choice_options = tuple()
@classmethod
def get_created_engines(cls):
"""Returns all created search engines."""
return list(cls._created_engines.items())
def __init__(self, engine_slug: str):
"""Initializes the search engine."""
# Check the slug is unique for this project.
if engine_slug in SearchBackend._created_engines:
raise SearchEngineError(f"A search engine has already been created with the slug {engine_slug}")
# Initialize this engine.
self._engine_slug = engine_slug
# Store a reference to this engine.
self.__class__._created_engines[engine_slug] = self
def get_registry(self): def get_registry(self):
r = {} r = {}
for app_label, models in registry['search'].items(): for app_label, models in registry['search'].items():
@ -47,6 +29,7 @@ class SearchBackend(object):
return r return r
def get_search_choices(self): def get_search_choices(self):
"""Return the set of choices for individual object types, organized by category."""
if not self._search_choice_options: if not self._search_choice_options:
# Organize choices by category # Organize choices by category
@ -66,14 +49,21 @@ class SearchBackend(object):
return self._search_choice_options return self._search_choice_options
def search(self, request, search_text, models=(), exclude=(), ranking=True, backend_name=None): def search(self, request, value, **kwargs):
"""Performs a search using the given text, returning a queryset of SearchEntry.""" """Execute a search query for the given value."""
raise NotImplementedError
def cache(self, instance):
"""Create or update the cached copy of an instance."""
raise NotImplementedError raise NotImplementedError
class FilterSetSearchBackend(SearchBackend): class FilterSetSearchBackend(SearchBackend):
"""
def search(self, request, search_text): Legacy search backend. Performs a discrete database query for each registered object type, using the FilterSet
class specified by the index for each.
"""
def search(self, request, value, **kwargs):
results = [] results = []
search_registry = self.get_registry() search_registry = self.get_registry()
@ -97,7 +87,7 @@ class FilterSetSearchBackend(SearchBackend):
continue continue
# Construct the results table for this object type # Construct the results table for this object type
filtered_queryset = filterset({'q': search_text}, queryset=queryset).qs filtered_queryset = filterset({'q': value}, queryset=queryset).qs
table = table(filtered_queryset, orderable=False) table = table(filtered_queryset, orderable=False)
table.paginate(per_page=SEARCH_MAX_RESULTS) table.paginate(per_page=SEARCH_MAX_RESULTS)
@ -105,36 +95,31 @@ class FilterSetSearchBackend(SearchBackend):
results.append({ results.append({
'name': queryset.model._meta.verbose_name_plural, 'name': queryset.model._meta.verbose_name_plural,
'table': table, 'table': table,
'url': f"{reverse(url)}?q={search_text}" 'url': f"{reverse(url)}?q={value}"
}) })
return results return results
def cache(self, instance):
# This backend does not utilize a cache
pass
def get_backend(backend_name=None):
"""Initializes and returns the search backend."""
global _backends_cache
if not backend_name:
backend_name = getattr(settings, "SEARCH_BACKEND", "netbox.search.backends.FilterSetSearchBackend")
# Try to use the cached backend. def get_backend():
if backend_name in _backends_cache: """Initializes and returns the configured search backend."""
return _backends_cache[backend_name] backend_name = settings.SEARCH_BACKEND
# Load the backend class. # Load the backend class
backend_module_name, backend_cls_name = backend_name.rsplit(".", 1) backend_module_name, backend_cls_name = backend_name.rsplit('.', 1)
backend_module = import_module(backend_module_name) backend_module = import_module(backend_module_name)
try: try:
backend_cls = getattr(backend_module, backend_cls_name) backend_cls = getattr(backend_module, backend_cls_name)
except AttributeError: except AttributeError:
raise ImproperlyConfigured(f"Could not find a class named {backend_module_name} in {backend_cls_name}") raise ImproperlyConfigured(f"Could not find a class named {backend_module_name} in {backend_cls_name}")
# Initialize the backend. # Initialize and return the backend instance
backend = backend_cls("default") return backend_cls()
_backends_cache[backend_name] = backend
return backend
# The main search methods.
default_search_engine = get_backend() default_search_engine = get_backend()
search = default_search_engine.search search = default_search_engine.search

View File

@ -121,6 +121,7 @@ REMOTE_AUTH_GROUP_SEPARATOR = getattr(configuration, 'REMOTE_AUTH_GROUP_SEPARATO
REPORTS_ROOT = getattr(configuration, 'REPORTS_ROOT', os.path.join(BASE_DIR, 'reports')).rstrip('/') REPORTS_ROOT = getattr(configuration, 'REPORTS_ROOT', os.path.join(BASE_DIR, 'reports')).rstrip('/')
RQ_DEFAULT_TIMEOUT = getattr(configuration, 'RQ_DEFAULT_TIMEOUT', 300) RQ_DEFAULT_TIMEOUT = getattr(configuration, 'RQ_DEFAULT_TIMEOUT', 300)
SCRIPTS_ROOT = getattr(configuration, 'SCRIPTS_ROOT', os.path.join(BASE_DIR, 'scripts')).rstrip('/') SCRIPTS_ROOT = getattr(configuration, 'SCRIPTS_ROOT', os.path.join(BASE_DIR, 'scripts')).rstrip('/')
SEARCH_BACKEND = getattr(configuration, 'SEARCH_BACKEND', 'netbox.search.backends.FilterSetSearchBackend')
SENTRY_DSN = getattr(configuration, 'SENTRY_DSN', DEFAULT_SENTRY_DSN) SENTRY_DSN = getattr(configuration, 'SENTRY_DSN', DEFAULT_SENTRY_DSN)
SENTRY_ENABLED = getattr(configuration, 'SENTRY_ENABLED', False) SENTRY_ENABLED = getattr(configuration, 'SENTRY_ENABLED', False)
SENTRY_SAMPLE_RATE = getattr(configuration, 'SENTRY_SAMPLE_RATE', 1.0) SENTRY_SAMPLE_RATE = getattr(configuration, 'SENTRY_SAMPLE_RATE', 1.0)