mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-24 16:26:09 -06:00
Update docs & improve plugin support
This commit is contained in:
parent
7201bc1d9e
commit
3750659c37
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user