diff --git a/netbox/circuits/search_indexes.py b/netbox/circuits/search_indexes.py index 5077dba0f..76f4d4f12 100644 --- a/netbox/circuits/search_indexes.py +++ b/netbox/circuits/search_indexes.py @@ -12,6 +12,7 @@ class ProviderIndex(SearchMixin): filterset = circuits.filtersets.ProviderFilterSet table = circuits.tables.ProviderTable url = 'circuits:provider_list' + choice_header = 'Circuits' class CircuitIndex(SearchMixin): @@ -22,6 +23,7 @@ class CircuitIndex(SearchMixin): filterset = circuits.filtersets.CircuitFilterSet table = circuits.tables.CircuitTable url = 'circuits:circuit_list' + choice_header = 'Circuits' class ProviderNetworkIndex(SearchMixin): @@ -30,6 +32,7 @@ class ProviderNetworkIndex(SearchMixin): filterset = circuits.filtersets.ProviderNetworkFilterSet table = circuits.tables.ProviderNetworkTable url = 'circuits:providernetwork_list' + choice_header = 'Circuits' CIRCUIT_SEARCH_TYPES = { diff --git a/netbox/dcim/search_indexes.py b/netbox/dcim/search_indexes.py index d98f956f7..65019c3d0 100644 --- a/netbox/dcim/search_indexes.py +++ b/netbox/dcim/search_indexes.py @@ -25,6 +25,7 @@ class SiteIndex(SearchMixin): filterset = dcim.filtersets.SiteFilterSet table = dcim.tables.SiteTable url = 'dcim:site_list' + choice_header = 'DCIM' class RackIndex(SearchMixin): @@ -35,6 +36,7 @@ class RackIndex(SearchMixin): filterset = dcim.filtersets.RackFilterSet table = dcim.tables.RackTable url = 'dcim:rack_list' + choice_header = 'DCIM' class RackReservationIndex(SearchMixin): @@ -43,6 +45,7 @@ class RackReservationIndex(SearchMixin): filterset = dcim.filtersets.RackReservationFilterSet table = dcim.tables.RackReservationTable url = 'dcim:rackreservation_list' + choice_header = 'DCIM' class LocationIndex(SearchMixin): @@ -57,6 +60,7 @@ class LocationIndex(SearchMixin): filterset = dcim.filtersets.LocationFilterSet table = dcim.tables.LocationTable url = 'dcim:location_list' + choice_header = 'DCIM' class DeviceTypeIndex(SearchMixin): @@ -67,6 +71,7 @@ class DeviceTypeIndex(SearchMixin): filterset = dcim.filtersets.DeviceTypeFilterSet table = dcim.tables.DeviceTypeTable url = 'dcim:devicetype_list' + choice_header = 'DCIM' class DeviceIndex(SearchMixin): @@ -84,6 +89,7 @@ class DeviceIndex(SearchMixin): filterset = dcim.filtersets.DeviceFilterSet table = dcim.tables.DeviceTable url = 'dcim:device_list' + choice_header = 'DCIM' class ModuleTypeIndex(SearchMixin): @@ -94,6 +100,7 @@ class ModuleTypeIndex(SearchMixin): filterset = dcim.filtersets.ModuleTypeFilterSet table = dcim.tables.ModuleTypeTable url = 'dcim:moduletype_list' + choice_header = 'DCIM' class ModuleIndex(SearchMixin): @@ -106,6 +113,7 @@ class ModuleIndex(SearchMixin): filterset = dcim.filtersets.ModuleFilterSet table = dcim.tables.ModuleTable url = 'dcim:module_list' + choice_header = 'DCIM' class VirtualChassisIndex(SearchMixin): @@ -116,6 +124,7 @@ class VirtualChassisIndex(SearchMixin): filterset = dcim.filtersets.VirtualChassisFilterSet table = dcim.tables.VirtualChassisTable url = 'dcim:virtualchassis_list' + choice_header = 'DCIM' class CableIndex(SearchMixin): @@ -124,6 +133,7 @@ class CableIndex(SearchMixin): filterset = dcim.filtersets.CableFilterSet table = dcim.tables.CableTable url = 'dcim:cable_list' + choice_header = 'DCIM' class PowerFeedIndex(SearchMixin): @@ -132,6 +142,7 @@ class PowerFeedIndex(SearchMixin): filterset = dcim.filtersets.PowerFeedFilterSet table = dcim.tables.PowerFeedTable url = 'dcim:powerfeed_list' + choice_header = 'DCIM' DCIM_SEARCH_TYPES = { diff --git a/netbox/extras/search_indexes.py b/netbox/extras/search_indexes.py index 195fb3960..7b5014cfe 100644 --- a/netbox/extras/search_indexes.py +++ b/netbox/extras/search_indexes.py @@ -12,6 +12,7 @@ class JournalEntryIndex(SearchMixin): filterset = extras.filtersets.JournalEntryFilterSet table = extras.tables.JournalEntryTable url = 'extras:journalentry_list' + choice_header = 'Journal' JOURNAL_SEARCH_TYPES = { diff --git a/netbox/ipam/search_indexes.py b/netbox/ipam/search_indexes.py index 5e745f695..32e14292b 100644 --- a/netbox/ipam/search_indexes.py +++ b/netbox/ipam/search_indexes.py @@ -12,6 +12,7 @@ class VRFIndex(SearchMixin): filterset = ipam.filtersets.VRFFilterSet table = ipam.tables.VRFTable url = 'ipam:vrf_list' + choice_header = 'IPAM' class AggregateIndex(SearchMixin): @@ -20,6 +21,7 @@ class AggregateIndex(SearchMixin): filterset = ipam.filtersets.AggregateFilterSet table = ipam.tables.AggregateTable url = 'ipam:aggregate_list' + choice_header = 'IPAM' class PrefixIndex(SearchMixin): @@ -30,6 +32,7 @@ class PrefixIndex(SearchMixin): filterset = ipam.filtersets.PrefixFilterSet table = ipam.tables.PrefixTable url = 'ipam:prefix_list' + choice_header = 'IPAM' class IPAddressIndex(SearchMixin): @@ -38,6 +41,7 @@ class IPAddressIndex(SearchMixin): filterset = ipam.filtersets.IPAddressFilterSet table = ipam.tables.IPAddressTable url = 'ipam:ipaddress_list' + choice_header = 'IPAM' class VLANIndex(SearchMixin): @@ -46,6 +50,7 @@ class VLANIndex(SearchMixin): filterset = ipam.filtersets.VLANFilterSet table = ipam.tables.VLANTable url = 'ipam:vlan_list' + choice_header = 'IPAM' class ASNIndex(SearchMixin): @@ -54,6 +59,7 @@ class ASNIndex(SearchMixin): filterset = ipam.filtersets.ASNFilterSet table = ipam.tables.ASNTable url = 'ipam:asn_list' + choice_header = 'IPAM' class ServiceIndex(SearchMixin): @@ -62,6 +68,7 @@ class ServiceIndex(SearchMixin): filterset = ipam.filtersets.ServiceFilterSet table = ipam.tables.ServiceTable url = 'ipam:service_list' + choice_header = 'IPAM' IPAM_SEARCH_TYPES = { diff --git a/netbox/search/apps.py b/netbox/search/apps.py index cfb4b2e6e..4d47d8a52 100644 --- a/netbox/search/apps.py +++ b/netbox/search/apps.py @@ -39,8 +39,8 @@ class SearchConfig(AppConfig): submodule_name = "search_indexes" if module_has_submodule(module, submodule_name): module_name = f"{name}.{submodule_name}" - for cls_name, cls_obj in inspect.getmembers(sys.modules[module_name]): - if inspect.isclass(cls_obj) and getattr(cls_obj, "search_index", False) and getattr(cls_obj, "model", None): + for cls_name, cls_obj in inspect.getmembers(sys.modules[module_name], predicate=inspect.isclass): + if getattr(cls_obj, "search_index", False) and getattr(cls_obj, "model", None): cls_name = cls_obj.model.__name__.lower() if not default_search_engine.is_registered(cls_name, cls_obj): default_search_engine.register(cls_name, cls_obj) diff --git a/netbox/search/backends.py b/netbox/search/backends.py index 69fb50979..cc68fe105 100644 --- a/netbox/search/backends.py +++ b/netbox/search/backends.py @@ -20,7 +20,8 @@ class SearchBackend(object): """A search engine capable of performing multi-table searches.""" _created_engines: dict = dict() - _search_choices = tuple() + _search_choices = {} + _search_choice_options = tuple() @classmethod def get_created_engines(cls): @@ -57,6 +58,13 @@ class SearchBackend(object): self._registered_models[key] = model + # add to the search choices + if model.choice_header not in self._search_choices: + self._search_choices[model.choice_header] = {} + + if key not in self._search_choices[model.choice_header]: + self._search_choices[model.choice_header][key] = model.queryset.model._meta.verbose_name_plural + # Connect to the signalling framework. if self._use_hooks(): post_save.connect(self._post_save_receiver, model) @@ -68,22 +76,21 @@ class SearchBackend(object): # Signalling hooks. def get_search_choices(self): - if self._search_choices: - return self._search_choices + if self._search_choice_options: + return self._search_choice_options result = list() result.append(('', 'All Objects')) - for category, items in self.get_registry().items(): + for category, items in self._search_choices.items(): subcategories = list() - for slug, obj in items.items(): - name = obj.queryset.model._meta.verbose_name_plural + for slug, verbose_name in items.items(): + name = verbose_name name = name[0].upper() + name[1:] subcategories.append((slug, name)) result.append((category, tuple(subcategories))) - self._search_choices = tuple(result) - print(self._search_choices) - return self._search_choices + self._search_choice_options = tuple(result) + return self._search_choice_options def _use_hooks(self): raise NotImplementedError diff --git a/netbox/tenancy/search_indexes.py b/netbox/tenancy/search_indexes.py index 423e15ff9..c6ddc38fa 100644 --- a/netbox/tenancy/search_indexes.py +++ b/netbox/tenancy/search_indexes.py @@ -7,23 +7,23 @@ from utilities.utils import count_related class TenantIndex(SearchMixin): - def __init__(self): - self.model = Tenant - self.queryset = Tenant.objects.prefetch_related('group') - self.filterset = tenancy.filtersets.TenantFilterSet - self.table = tenancy.tables.TenantTable - self.url = 'tenancy:tenant_list' + model = Tenant + queryset = Tenant.objects.prefetch_related('group') + filterset = tenancy.filtersets.TenantFilterSet + table = tenancy.tables.TenantTable + url = 'tenancy:tenant_list' + choice_header = 'Tenancy' class ContactIndex(SearchMixin): - def __init__(self): - self.model = Contact - self.queryset = Contact.objects.prefetch_related('group', 'assignments').annotate( - assignment_count=count_related(ContactAssignment, 'contact') - ) - self.filterset = tenancy.filtersets.ContactFilterSet - self.table = tenancy.tables.ContactTable - self.url = 'tenancy:contact_list' + model = Contact + queryset = Contact.objects.prefetch_related('group', 'assignments').annotate( + assignment_count=count_related(ContactAssignment, 'contact') + ) + filterset = tenancy.filtersets.ContactFilterSet + table = tenancy.tables.ContactTable + url = 'tenancy:contact_list' + choice_header = 'Tenancy' TENANCY_SEARCH_TYPES = { diff --git a/netbox/virtualization/search_indexes.py b/netbox/virtualization/search_indexes.py index ef8839c12..2bb2d57d7 100644 --- a/netbox/virtualization/search_indexes.py +++ b/netbox/virtualization/search_indexes.py @@ -7,30 +7,30 @@ from virtualization.models import Cluster, Device, VirtualMachine class ClusterIndex(SearchMixin): - def __init__(self): - self.model = Cluster - self.queryset = Cluster.objects.prefetch_related('type', 'group').annotate( - device_count=count_related(Device, 'cluster'), vm_count=count_related(VirtualMachine, 'cluster') - ) - self.filterset = virtualization.filtersets.ClusterFilterSet - self.table = virtualization.tables.ClusterTable - self.url = 'virtualization:cluster_list' + model = Cluster + queryset = Cluster.objects.prefetch_related('type', 'group').annotate( + device_count=count_related(Device, 'cluster'), vm_count=count_related(VirtualMachine, 'cluster') + ) + filterset = virtualization.filtersets.ClusterFilterSet + table = virtualization.tables.ClusterTable + url = 'virtualization:cluster_list' + choice_header = 'Virtualization' class VirtualMachineIndex(SearchMixin): - def __init__(self): - self.model = VirtualMachine - self.queryset = VirtualMachine.objects.prefetch_related( - 'cluster', - 'tenant', - 'tenant__group', - 'platform', - 'primary_ip4', - 'primary_ip6', - ) - self.filterset = virtualization.filtersets.VirtualMachineFilterSet - self.table = virtualization.tables.VirtualMachineTable - self.url = 'virtualization:virtualmachine_list' + model = VirtualMachine + queryset = VirtualMachine.objects.prefetch_related( + 'cluster', + 'tenant', + 'tenant__group', + 'platform', + 'primary_ip4', + 'primary_ip6', + ) + filterset = virtualization.filtersets.VirtualMachineFilterSet + table = virtualization.tables.VirtualMachineTable + url = 'virtualization:virtualmachine_list' + choice_header = 'Virtualization' VIRTUALIZATION_SEARCH_TYPES = { diff --git a/netbox/wireless/search_indexes.py b/netbox/wireless/search_indexes.py index 366156323..1878ef753 100644 --- a/netbox/wireless/search_indexes.py +++ b/netbox/wireless/search_indexes.py @@ -15,6 +15,7 @@ class WirelessLANIndex(SearchMixin): filterset = wireless.filtersets.WirelessLANFilterSet table = wireless.tables.WirelessLANTable url = 'wireless:wirelesslan_list' + choice_header = 'Wireless' class WirelessLinkIndex(SearchMixin): @@ -23,6 +24,7 @@ class WirelessLinkIndex(SearchMixin): filterset = wireless.filtersets.WirelessLinkFilterSet table = wireless.tables.WirelessLinkTable url = 'wireless:wirelesslink_list' + choice_header = 'Wireless' WIRELESS_SEARCH_TYPES = {