Update docs & improve plugin support

This commit is contained in:
jeremystretch 2022-10-10 12:25:53 -04:00
parent 7201bc1d9e
commit 3750659c37
4 changed files with 40 additions and 24 deletions

View File

@ -1,31 +1,29 @@
# Search # Search
If you want your plugin models to appear in search results, you will need to create a search index for the models. Search indexes must be in defined in a search_indexes.py file. Plugins can define and register their own models to extend NetBox's core search functionality. Typically, a plugin will include a file named `search.py`, which holds all search indexes for its models (see the example below).
As an example, lets define a search_index for the MyModel object defined before:
```python ```python
# search_indexes.py # search.py
from .filters import MyFilterSet from netbox.search import SearchMixin
from .filters import MyModelFilterSet
from .tables import MyModelTable from .tables import MyModelTable
from .models import MyModel from .models import MyModel
from search.models import SearchMixin
class MyModelIndex(SearchMixin): class MyModelIndex(SearchMixin):
model = MyModel model = MyModel
queryset = MyModel.objects.all() queryset = MyModel.objects.all()
filterset = MyModelFilterSet filterset = MyModelFilterSet
table = MyModelTable table = MyModelTable
url = 'plugins:netbox_mymodel:mymodel_list' url = 'plugins:myplugin:mymodel_list'
choice_header = 'MyModel'
``` ```
All the fields must be defined as follows: To register one or more indexes with NetBox, define a list named `indexes` at the end of this file:
* `model` - The model that will be searched (see: [Models](./models.md)). ```python
* `queryset` - The queryset on the model that will be passed to the filterset. indexes = [MyModelIndex]
* `filterset` - The filterset for the model that contains the search method (see: [Filters & Filter Sets](./filtersets.md)). ```
* `table` - Table that is used in the list view (see: (see: [Tables](./tables.md)).
* `url` - URL to the list view to show search results. !!! tip
* `choice_header` - The header that will appear in the search drop-down to group menu items together. The path to the list of search indexes can be modified by setting `search_indexes` in the PluginConfig instance.
::: netbox.search.SearchIndex

View File

@ -61,7 +61,7 @@ class PluginConfig(AppConfig):
# Default integration paths. Plugin authors can override these to customize the paths to # Default integration paths. Plugin authors can override these to customize the paths to
# integrated components. # integrated components.
search = 'search.indexes' search_indexes = 'search.indexes'
graphql_schema = 'graphql.schema' graphql_schema = 'graphql.schema'
menu = 'navigation.menu' menu = 'navigation.menu'
menu_items = 'navigation.menu_items' menu_items = 'navigation.menu_items'
@ -72,7 +72,7 @@ class PluginConfig(AppConfig):
plugin_name = self.name.rsplit('.', 1)[-1] plugin_name = self.name.rsplit('.', 1)[-1]
# Search extensions # Search extensions
search_indexes = import_object(f"{self.__module__}.{self.search}") or [] search_indexes = import_object(f"{self.__module__}.{self.search_indexes}") or []
for idx in search_indexes: for idx in search_indexes:
register_search()(idx) register_search()(idx)

View File

@ -4,11 +4,17 @@ from extras.registry import registry
class SearchIndex: class SearchIndex:
""" """
Base class for building search indexes. Base class for building search indexes.
Attrs:
model: The model class for which this index is used.
""" """
search_index = True model = None
@classmethod @classmethod
def get_category(cls): def get_category(cls):
"""
Return the title of the search category under which this model is registered.
"""
if hasattr(cls, 'category'): if hasattr(cls, 'category'):
return cls.category return cls.category
return cls.model._meta.app_config.verbose_name return cls.model._meta.app_config.verbose_name

View File

@ -71,7 +71,7 @@ class SearchBackend(object):
raise NotImplementedError raise NotImplementedError
class PostgresIcontainsSearchBackend(SearchBackend): class FilterSetSearchBackend(SearchBackend):
def search(self, request, search_text): def search(self, request, search_text):
results = [] results = []
@ -79,11 +79,23 @@ class PostgresIcontainsSearchBackend(SearchBackend):
search_registry = self.get_registry() search_registry = self.get_registry()
for obj_type in search_registry.keys(): for obj_type in search_registry.keys():
queryset = search_registry[obj_type].queryset.restrict(request.user, 'view') queryset = search_registry[obj_type].queryset
filterset = search_registry[obj_type].filterset
table = search_registry[obj_type].table
url = search_registry[obj_type].url url = search_registry[obj_type].url
# Restrict the queryset for the current user
if hasattr(queryset, 'restrict'):
queryset = queryset.restrict(request.user, 'view')
filterset = getattr(search_registry[obj_type], 'filterset', None)
if not filterset:
# This backend requires a FilterSet class for the model
continue
table = getattr(search_registry[obj_type], 'table', None)
if not table:
# This backend requires a Table class for the model
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': search_text}, queryset=queryset).qs
table = table(filtered_queryset, orderable=False) table = table(filtered_queryset, orderable=False)
@ -103,7 +115,7 @@ def get_backend(backend_name=None):
"""Initializes and returns the search backend.""" """Initializes and returns the search backend."""
global _backends_cache global _backends_cache
if not backend_name: if not backend_name:
backend_name = getattr(settings, "SEARCH_BACKEND", "netbox.search.backends.PostgresIcontainsSearchBackend") backend_name = getattr(settings, "SEARCH_BACKEND", "netbox.search.backends.FilterSetSearchBackend")
# Try to use the cached backend. # Try to use the cached backend.
if backend_name in _backends_cache: if backend_name in _backends_cache: