Cleanup & docs

This commit is contained in:
jeremystretch 2022-10-20 10:44:28 -04:00
parent 885e246fce
commit f67b63b539
14 changed files with 107 additions and 86 deletions

View File

@ -1,6 +1,27 @@
# Search
## Field Weight Guidance
NetBox v3.4 introduced a new global search mechanism, which employs the `extras.CachedValue` model to store discrete field values from many models in a single table.
## SearchIndex
To enable search support for a model, declare and register a subclass of `netbox.search.SearchIndex` for it. Typically, this will be done within an app's `search.py` module.
```python
from netbox.search import SearchIndex, register_search
@register_search
class MyModelIndex(SearchIndex):
model = MyModel
fields = (
('name', 100),
('description', 500),
('comments', 5000),
)
```
A SearchIndex subclass defines both its model and a list of two-tuples specifying which model fields to be indexed and the weight (precedence) associated with each. Guidance on weight assignment for fields is provided below.
### Field Weight Guidance
| Weight | Field Role | Examples |
|--------|--------------------------------------------------|----------------------------------------------------|

View File

@ -11,6 +11,10 @@
### New Features
#### New Global Search ([#10560](https://github.com/netbox-community/netbox/issues/10560))
NetBox's global search functionality has been completely overhauled and replaced by a new cache-based lookup.
#### Top-Level Plugin Navigation Menus ([#9071](https://github.com/netbox-community/netbox/issues/9071))
A new `PluginMenu` class has been introduced, which enables a plugin to inject a top-level menu in NetBox's navigation menu. This menu can have one or more groups of menu items, just like core items. Backward compatibility with the existing `menu_items` has been maintained.

View File

@ -2,7 +2,7 @@ from netbox.search import SearchIndex, register_search
from . import models
@register_search()
@register_search
class CircuitIndex(SearchIndex):
model = models.Circuit
fields = (
@ -12,7 +12,7 @@ class CircuitIndex(SearchIndex):
)
@register_search()
@register_search
class CircuitTerminationIndex(SearchIndex):
model = models.CircuitTermination
fields = (
@ -24,7 +24,7 @@ class CircuitTerminationIndex(SearchIndex):
)
@register_search()
@register_search
class CircuitTypeIndex(SearchIndex):
model = models.CircuitType
fields = (
@ -34,7 +34,7 @@ class CircuitTypeIndex(SearchIndex):
)
@register_search()
@register_search
class ProviderIndex(SearchIndex):
model = models.Provider
fields = (
@ -44,7 +44,7 @@ class ProviderIndex(SearchIndex):
)
@register_search()
@register_search
class ProviderNetworkIndex(SearchIndex):
model = models.ProviderNetwork
fields = (

View File

@ -2,7 +2,7 @@ from netbox.search import SearchIndex, register_search
from . import models
@register_search()
@register_search
class CableIndex(SearchIndex):
model = models.Cable
fields = (
@ -10,7 +10,7 @@ class CableIndex(SearchIndex):
)
@register_search()
@register_search
class ConsolePortIndex(SearchIndex):
model = models.ConsolePort
fields = (
@ -21,7 +21,7 @@ class ConsolePortIndex(SearchIndex):
)
@register_search()
@register_search
class ConsoleServerPortIndex(SearchIndex):
model = models.ConsoleServerPort
fields = (
@ -32,7 +32,7 @@ class ConsoleServerPortIndex(SearchIndex):
)
@register_search()
@register_search
class DeviceIndex(SearchIndex):
model = models.Device
fields = (
@ -43,7 +43,7 @@ class DeviceIndex(SearchIndex):
)
@register_search()
@register_search
class DeviceBayIndex(SearchIndex):
model = models.DeviceBay
fields = (
@ -53,7 +53,7 @@ class DeviceBayIndex(SearchIndex):
)
@register_search()
@register_search
class DeviceRoleIndex(SearchIndex):
model = models.DeviceRole
fields = (
@ -63,7 +63,7 @@ class DeviceRoleIndex(SearchIndex):
)
@register_search()
@register_search
class DeviceTypeIndex(SearchIndex):
model = models.DeviceType
fields = (
@ -73,7 +73,7 @@ class DeviceTypeIndex(SearchIndex):
)
@register_search()
@register_search
class FrontPortIndex(SearchIndex):
model = models.FrontPort
fields = (
@ -83,7 +83,7 @@ class FrontPortIndex(SearchIndex):
)
@register_search()
@register_search
class InterfaceIndex(SearchIndex):
model = models.Interface
fields = (
@ -97,7 +97,7 @@ class InterfaceIndex(SearchIndex):
)
@register_search()
@register_search
class InventoryItemIndex(SearchIndex):
model = models.InventoryItem
fields = (
@ -110,7 +110,7 @@ class InventoryItemIndex(SearchIndex):
)
@register_search()
@register_search
class LocationIndex(SearchIndex):
model = models.Location
fields = (
@ -120,7 +120,7 @@ class LocationIndex(SearchIndex):
)
@register_search()
@register_search
class ManufacturerIndex(SearchIndex):
model = models.Manufacturer
fields = (
@ -130,7 +130,7 @@ class ManufacturerIndex(SearchIndex):
)
@register_search()
@register_search
class ModuleIndex(SearchIndex):
model = models.Module
fields = (
@ -140,7 +140,7 @@ class ModuleIndex(SearchIndex):
)
@register_search()
@register_search
class ModuleBayIndex(SearchIndex):
model = models.ModuleBay
fields = (
@ -150,7 +150,7 @@ class ModuleBayIndex(SearchIndex):
)
@register_search()
@register_search
class ModuleTypeIndex(SearchIndex):
model = models.ModuleType
fields = (
@ -160,7 +160,7 @@ class ModuleTypeIndex(SearchIndex):
)
@register_search()
@register_search
class PlatformIndex(SearchIndex):
model = models.Platform
fields = (
@ -171,7 +171,7 @@ class PlatformIndex(SearchIndex):
)
@register_search()
@register_search
class PowerFeedIndex(SearchIndex):
model = models.PowerFeed
fields = (
@ -180,7 +180,7 @@ class PowerFeedIndex(SearchIndex):
)
@register_search()
@register_search
class PowerOutletIndex(SearchIndex):
model = models.PowerOutlet
fields = (
@ -190,7 +190,7 @@ class PowerOutletIndex(SearchIndex):
)
@register_search()
@register_search
class PowerPanelIndex(SearchIndex):
model = models.PowerPanel
fields = (
@ -198,7 +198,7 @@ class PowerPanelIndex(SearchIndex):
)
@register_search()
@register_search
class PowerPortIndex(SearchIndex):
model = models.PowerPort
fields = (
@ -210,7 +210,7 @@ class PowerPortIndex(SearchIndex):
)
@register_search()
@register_search
class RackIndex(SearchIndex):
model = models.Rack
fields = (
@ -222,7 +222,7 @@ class RackIndex(SearchIndex):
)
@register_search()
@register_search
class RackReservationIndex(SearchIndex):
model = models.RackReservation
fields = (
@ -230,7 +230,7 @@ class RackReservationIndex(SearchIndex):
)
@register_search()
@register_search
class RackRoleIndex(SearchIndex):
model = models.RackRole
fields = (
@ -240,7 +240,7 @@ class RackRoleIndex(SearchIndex):
)
@register_search()
@register_search
class RearPortIndex(SearchIndex):
model = models.RearPort
fields = (
@ -250,7 +250,7 @@ class RearPortIndex(SearchIndex):
)
@register_search()
@register_search
class RegionIndex(SearchIndex):
model = models.Region
fields = (
@ -260,7 +260,7 @@ class RegionIndex(SearchIndex):
)
@register_search()
@register_search
class SiteIndex(SearchIndex):
model = models.Site
fields = (
@ -274,7 +274,7 @@ class SiteIndex(SearchIndex):
)
@register_search()
@register_search
class SiteGroupIndex(SearchIndex):
model = models.SiteGroup
fields = (
@ -284,7 +284,7 @@ class SiteGroupIndex(SearchIndex):
)
@register_search()
@register_search
class VirtualChassisIndex(SearchIndex):
model = models.VirtualChassis
fields = (

View File

@ -75,7 +75,7 @@ class PluginConfig(AppConfig):
try:
search_indexes = import_string(f"{self.__module__}.{self.search_indexes}")
for idx in search_indexes:
register_search()(idx)
register_search(idx)
except ImportError:
pass

View File

@ -2,7 +2,7 @@ from netbox.search import SearchIndex, register_search
from . import models
@register_search()
@register_search
class JournalEntryIndex(SearchIndex):
model = models.JournalEntry
fields = (

View File

@ -2,7 +2,7 @@ from . import models
from netbox.search import SearchIndex, register_search
@register_search()
@register_search
class AggregateIndex(SearchIndex):
model = models.Aggregate
fields = (
@ -12,7 +12,7 @@ class AggregateIndex(SearchIndex):
)
@register_search()
@register_search
class ASNIndex(SearchIndex):
model = models.ASN
fields = (
@ -21,7 +21,7 @@ class ASNIndex(SearchIndex):
)
@register_search()
@register_search
class FHRPGroupIndex(SearchIndex):
model = models.FHRPGroup
fields = (
@ -31,7 +31,7 @@ class FHRPGroupIndex(SearchIndex):
)
@register_search()
@register_search
class IPAddressIndex(SearchIndex):
model = models.IPAddress
fields = (
@ -41,7 +41,7 @@ class IPAddressIndex(SearchIndex):
)
@register_search()
@register_search
class IPRangeIndex(SearchIndex):
model = models.IPRange
fields = (
@ -51,7 +51,7 @@ class IPRangeIndex(SearchIndex):
)
@register_search()
@register_search
class L2VPNIndex(SearchIndex):
model = models.L2VPN
fields = (
@ -61,7 +61,7 @@ class L2VPNIndex(SearchIndex):
)
@register_search()
@register_search
class PrefixIndex(SearchIndex):
model = models.Prefix
fields = (
@ -70,7 +70,7 @@ class PrefixIndex(SearchIndex):
)
@register_search()
@register_search
class RIRIndex(SearchIndex):
model = models.RIR
fields = (
@ -80,7 +80,7 @@ class RIRIndex(SearchIndex):
)
@register_search()
@register_search
class RoleIndex(SearchIndex):
model = models.Role
fields = (
@ -90,7 +90,7 @@ class RoleIndex(SearchIndex):
)
@register_search()
@register_search
class RouteTargetIndex(SearchIndex):
model = models.RouteTarget
fields = (
@ -99,7 +99,7 @@ class RouteTargetIndex(SearchIndex):
)
@register_search()
@register_search
class ServiceIndex(SearchIndex):
model = models.Service
fields = (
@ -108,7 +108,7 @@ class ServiceIndex(SearchIndex):
)
@register_search()
@register_search
class VLANIndex(SearchIndex):
model = models.VLAN
fields = (
@ -118,7 +118,7 @@ class VLANIndex(SearchIndex):
)
@register_search()
@register_search
class VLANGroupIndex(SearchIndex):
model = models.VLANGroup
fields = (
@ -129,7 +129,7 @@ class VLANGroupIndex(SearchIndex):
)
@register_search()
@register_search
class VRFIndex(SearchIndex):
model = models.VRF
fields = (

View File

@ -91,17 +91,14 @@ def get_indexer(model):
return registry['search'][app_label][model_name]
def register_search():
def register_search(cls):
"""
Decorator for registering a SearchIndex with a particular model.
"""
def _wrapper(cls):
model = cls.model
app_label = model._meta.app_label
model_name = model._meta.model_name
model = cls.model
app_label = model._meta.app_label
model_name = model._meta.model_name
registry['search'][app_label][model_name] = cls
registry['search'][app_label][model_name] = cls
return cls
return _wrapper
return cls

View File

@ -7,6 +7,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.db.models import F, Window
from django.db.models.functions import window
from django.db.models.signals import post_delete, post_save
from django.utils.module_loading import import_string
from extras.models import CachedValue, CustomField
from extras.registry import registry
@ -50,7 +51,7 @@ class SearchBackend:
return self._search_choice_options
def search(self, request, value, object_types=None, lookup=DEFAULT_LOOKUP_TYPE):
def search(self, value, user=None, object_types=None, lookup=DEFAULT_LOOKUP_TYPE):
"""
Search cached object representations for the given value.
"""
@ -102,9 +103,7 @@ class SearchBackend:
class CachedValueSearchBackend(SearchBackend):
def search(self, value, user=None, object_types=None, lookup=None):
if not lookup:
lookup = DEFAULT_LOOKUP_TYPE
def search(self, value, user=None, object_types=None, lookup=DEFAULT_LOOKUP_TYPE):
# Define the search parameters
params = {
@ -230,16 +229,13 @@ class CachedValueSearchBackend(SearchBackend):
def get_backend():
"""Initializes and returns the configured search backend."""
backend_name = settings.SEARCH_BACKEND
# Load the backend class
backend_module_name, backend_cls_name = backend_name.rsplit('.', 1)
backend_module = import_module(backend_module_name)
"""
Initializes and returns the configured search backend.
"""
try:
backend_cls = getattr(backend_module, backend_cls_name)
backend_cls = import_string(settings.SEARCH_BACKEND)
except AttributeError:
raise ImproperlyConfigured(f"Could not find a class named {backend_module_name} in {backend_cls_name}")
raise ImproperlyConfigured(f"Failed to import configured SEARCH_BACKEND: {settings.SEARCH_BACKEND}")
# Initialize and return the backend instance
return backend_cls()

View File

@ -222,7 +222,9 @@ class SearchTable(tables.Table):
super().__init__(data, **kwargs)
def render_field(self, value, record):
return bettertitle(record.object._meta.get_field(value).verbose_name)
if hasattr(record.object, value):
return bettertitle(record.object._meta.get_field(value).verbose_name)
return value
def render_value(self, value):
if not self.highlight:

View File

@ -167,11 +167,12 @@ class SearchView(View):
app_label, model_name = obj_type.split('.')
object_types.append(ContentType.objects.get_by_natural_key(app_label, model_name))
lookup = form.cleaned_data['lookup'] or LookupTypes.PARTIAL
results = search_backend.search(
form.cleaned_data['q'],
user=request.user,
object_types=object_types,
lookup=form.cleaned_data['lookup']
lookup=lookup
)
if form.cleaned_data['lookup'] != LookupTypes.EXACT:

View File

@ -2,7 +2,7 @@ from netbox.search import SearchIndex, register_search
from . import models
@register_search()
@register_search
class ContactIndex(SearchIndex):
model = models.Contact
fields = (
@ -16,7 +16,7 @@ class ContactIndex(SearchIndex):
)
@register_search()
@register_search
class ContactGroupIndex(SearchIndex):
model = models.ContactGroup
fields = (
@ -26,7 +26,7 @@ class ContactGroupIndex(SearchIndex):
)
@register_search()
@register_search
class ContactRoleIndex(SearchIndex):
model = models.ContactRole
fields = (
@ -36,7 +36,7 @@ class ContactRoleIndex(SearchIndex):
)
@register_search()
@register_search
class TenantIndex(SearchIndex):
model = models.Tenant
fields = (
@ -47,7 +47,7 @@ class TenantIndex(SearchIndex):
)
@register_search()
@register_search
class TenantGroupIndex(SearchIndex):
model = models.TenantGroup
fields = (

View File

@ -2,7 +2,7 @@ from netbox.search import SearchIndex, register_search
from . import models
@register_search()
@register_search
class ClusterIndex(SearchIndex):
model = models.Cluster
fields = (
@ -11,7 +11,7 @@ class ClusterIndex(SearchIndex):
)
@register_search()
@register_search
class ClusterGroupIndex(SearchIndex):
model = models.ClusterGroup
fields = (
@ -21,7 +21,7 @@ class ClusterGroupIndex(SearchIndex):
)
@register_search()
@register_search
class ClusterTypeIndex(SearchIndex):
model = models.ClusterType
fields = (
@ -31,7 +31,7 @@ class ClusterTypeIndex(SearchIndex):
)
@register_search()
@register_search
class VirtualMachineIndex(SearchIndex):
model = models.VirtualMachine
fields = (
@ -40,7 +40,7 @@ class VirtualMachineIndex(SearchIndex):
)
@register_search()
@register_search
class VMInterfaceIndex(SearchIndex):
model = models.VMInterface
fields = (

View File

@ -2,7 +2,7 @@ from netbox.search import SearchIndex, register_search
from . import models
@register_search()
@register_search
class WirelessLANIndex(SearchIndex):
model = models.WirelessLAN
fields = (
@ -12,7 +12,7 @@ class WirelessLANIndex(SearchIndex):
)
@register_search()
@register_search
class WirelessLANGroupIndex(SearchIndex):
model = models.WirelessLANGroup
fields = (
@ -22,7 +22,7 @@ class WirelessLANGroupIndex(SearchIndex):
)
@register_search()
@register_search
class WirelessLinkIndex(SearchIndex):
model = models.WirelessLink
fields = (