1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Closes #14134: Display additional object attributes in global search results (#14154)

* WIP

* Add display_attrs for all indexers

* Linkify object attributes

* Clean up prefetch logic

* Use tooltips for display attributes

* Simplify template code

* Introduce get_indexer() utility function

* Add  to examples in docs

* Use tooltips to display long strings
This commit is contained in:
Jeremy Stretch
2023-11-09 16:21:09 -05:00
committed by GitHub
parent 2562c8745c
commit 3d20276f55
15 changed files with 165 additions and 7 deletions

View File

@ -17,6 +17,7 @@ class MyModelIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('site', 'device', 'status', 'description')
``` ```
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. 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.

View File

@ -14,8 +14,11 @@ class MyModelIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('site', 'device', 'status', 'description')
``` ```
Fields listed in `display_attrs` will not be cached for search, but will be displayed alongside the object when it appears in global search results. This is helpful for conveying to the user additional information about an object.
To register one or more indexes with NetBox, define a list named `indexes` at the end of this file: To register one or more indexes with NetBox, define a list named `indexes` at the end of this file:
```python ```python

View File

@ -10,6 +10,7 @@ class CircuitIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('provider', 'provider_account', 'type', 'status', 'tenant', 'description')
@register_search @register_search
@ -22,6 +23,7 @@ class CircuitTerminationIndex(SearchIndex):
('port_speed', 2000), ('port_speed', 2000),
('upstream_speed', 2000), ('upstream_speed', 2000),
) )
display_attrs = ('circuit', 'site', 'provider_network', 'description')
@register_search @register_search
@ -32,6 +34,7 @@ class CircuitTypeIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)
@register_search @register_search
@ -42,6 +45,7 @@ class ProviderIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('description',)
class ProviderAccountIndex(SearchIndex): class ProviderAccountIndex(SearchIndex):
@ -51,6 +55,7 @@ class ProviderAccountIndex(SearchIndex):
('account', 200), ('account', 200),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('provider', 'account', 'description')
@register_search @register_search
@ -62,3 +67,4 @@ class ProviderNetworkIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('provider', 'service_id', 'description')

View File

@ -11,6 +11,7 @@ class DataSourceIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('type', 'status', 'description')
@register_search @register_search

View File

@ -10,6 +10,7 @@ class CableIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('type', 'status', 'tenant', 'label', 'description')
@register_search @register_search
@ -21,6 +22,7 @@ class ConsolePortIndex(SearchIndex):
('description', 500), ('description', 500),
('speed', 2000), ('speed', 2000),
) )
display_attrs = ('device', 'label', 'description')
@register_search @register_search
@ -32,6 +34,7 @@ class ConsoleServerPortIndex(SearchIndex):
('description', 500), ('description', 500),
('speed', 2000), ('speed', 2000),
) )
display_attrs = ('device', 'label', 'description')
@register_search @register_search
@ -44,6 +47,9 @@ class DeviceIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = (
'site', 'location', 'rack', 'device_type', 'role', 'tenant', 'platform', 'serial', 'asset_tag', 'description',
)
@register_search @register_search
@ -54,6 +60,7 @@ class DeviceBayIndex(SearchIndex):
('label', 200), ('label', 200),
('description', 500), ('description', 500),
) )
display_attrs = ('device', 'label', 'description')
@register_search @register_search
@ -64,6 +71,7 @@ class DeviceRoleIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)
@register_search @register_search
@ -75,6 +83,7 @@ class DeviceTypeIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('manufacturer', 'part_number', 'description')
@register_search @register_search
@ -85,6 +94,7 @@ class FrontPortIndex(SearchIndex):
('label', 200), ('label', 200),
('description', 500), ('description', 500),
) )
display_attrs = ('device', 'label', 'description')
@register_search @register_search
@ -99,6 +109,7 @@ class InterfaceIndex(SearchIndex):
('mtu', 2000), ('mtu', 2000),
('speed', 2000), ('speed', 2000),
) )
display_attrs = ('device', 'label', 'description')
@register_search @register_search
@ -112,6 +123,7 @@ class InventoryItemIndex(SearchIndex):
('description', 500), ('description', 500),
('part_id', 2000), ('part_id', 2000),
) )
display_attrs = ('device', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description')
@register_search @register_search
@ -122,6 +134,7 @@ class LocationIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('site', 'status', 'tenant', 'description')
@register_search @register_search
@ -132,6 +145,7 @@ class ManufacturerIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)
@register_search @register_search
@ -143,6 +157,7 @@ class ModuleIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('device', 'module_bay', 'module_type', 'status', 'serial', 'asset_tag', 'description')
@register_search @register_search
@ -153,6 +168,7 @@ class ModuleBayIndex(SearchIndex):
('label', 200), ('label', 200),
('description', 500), ('description', 500),
) )
display_attrs = ('device', 'label', 'position', 'description')
@register_search @register_search
@ -164,6 +180,7 @@ class ModuleTypeIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('manufacturer', 'model', 'part_number', 'description')
@register_search @register_search
@ -174,6 +191,7 @@ class PlatformIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('manufacturer', 'description')
@register_search @register_search
@ -184,6 +202,7 @@ class PowerFeedIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('power_panel', 'rack', 'status', 'description')
@register_search @register_search
@ -194,6 +213,7 @@ class PowerOutletIndex(SearchIndex):
('label', 200), ('label', 200),
('description', 500), ('description', 500),
) )
display_attrs = ('device', 'label', 'description')
@register_search @register_search
@ -204,6 +224,7 @@ class PowerPanelIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('site', 'location', 'description')
@register_search @register_search
@ -216,6 +237,7 @@ class PowerPortIndex(SearchIndex):
('maximum_draw', 2000), ('maximum_draw', 2000),
('allocated_draw', 2000), ('allocated_draw', 2000),
) )
display_attrs = ('device', 'label', 'description')
@register_search @register_search
@ -229,6 +251,7 @@ class RackIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('site', 'location', 'facility_id', 'tenant', 'status', 'role', 'description')
@register_search @register_search
@ -238,6 +261,7 @@ class RackReservationIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('rack', 'tenant', 'user', 'description')
@register_search @register_search
@ -248,6 +272,7 @@ class RackRoleIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('device', 'label', 'description',)
@register_search @register_search
@ -258,6 +283,7 @@ class RearPortIndex(SearchIndex):
('label', 200), ('label', 200),
('description', 500), ('description', 500),
) )
display_attrs = ('device', 'label', 'description')
@register_search @register_search
@ -268,6 +294,7 @@ class RegionIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('parent', 'description')
@register_search @register_search
@ -282,6 +309,7 @@ class SiteIndex(SearchIndex):
('shipping_address', 2000), ('shipping_address', 2000),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('region', 'group', 'status', 'description')
@register_search @register_search
@ -292,6 +320,7 @@ class SiteGroupIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('parent', 'description')
@register_search @register_search
@ -303,6 +332,7 @@ class VirtualChassisIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('master', 'domain', 'description')
@register_search @register_search
@ -314,3 +344,4 @@ class VirtualDeviceContextIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('device', 'status', 'identifier', 'description')

View File

@ -4,7 +4,10 @@ from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from netbox.search.utils import get_indexer
from netbox.registry import registry
from utilities.fields import RestrictedGenericForeignKey from utilities.fields import RestrictedGenericForeignKey
from utilities.utils import content_type_identifier
from ..fields import CachedValueField from ..fields import CachedValueField
__all__ = ( __all__ = (
@ -58,3 +61,19 @@ class CachedValue(models.Model):
def __str__(self): def __str__(self):
return f'{self.object_type} {self.object_id}: {self.field}={self.value}' return f'{self.object_type} {self.object_id}: {self.field}={self.value}'
@property
def display_attrs(self):
"""
Render any display attributes associated with this search result.
"""
indexer = get_indexer(self.object_type)
attrs = {}
for attr in indexer.display_attrs:
name = self.object._meta.get_field(attr).verbose_name
if value := getattr(self.object, attr):
if display_func := getattr(self.object, f'get_{attr}_display', None):
attrs[name] = display_func()
else:
attrs[name] = value
return attrs

View File

@ -11,6 +11,7 @@ class AggregateIndex(SearchIndex):
('date_added', 2000), ('date_added', 2000),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('rir', 'tenant', 'description')
@register_search @register_search
@ -20,6 +21,7 @@ class ASNIndex(SearchIndex):
('asn', 100), ('asn', 100),
('description', 500), ('description', 500),
) )
display_attrs = ('rir', 'tenant', 'description')
@register_search @register_search
@ -28,6 +30,7 @@ class ASNRangeIndex(SearchIndex):
fields = ( fields = (
('description', 500), ('description', 500),
) )
display_attrs = ('rir', 'tenant', 'description')
@register_search @register_search
@ -39,6 +42,7 @@ class FHRPGroupIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('protocol', 'auth_type', 'description')
@register_search @register_search
@ -50,6 +54,7 @@ class IPAddressIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('vrf', 'tenant', 'status', 'role', 'description')
@register_search @register_search
@ -61,6 +66,7 @@ class IPRangeIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('vrf', 'tenant', 'status', 'role', 'description')
@register_search @register_search
@ -72,6 +78,7 @@ class L2VPNIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('type', 'identifier', 'tenant', 'description')
@register_search @register_search
@ -82,6 +89,7 @@ class PrefixIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'description')
@register_search @register_search
@ -92,6 +100,7 @@ class RIRIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)
@register_search @register_search
@ -102,6 +111,7 @@ class RoleIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)
@register_search @register_search
@ -112,6 +122,7 @@ class RouteTargetIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('tenant', 'description')
@register_search @register_search
@ -122,6 +133,7 @@ class ServiceIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('device', 'virtual_machine', 'description')
@register_search @register_search
@ -132,6 +144,7 @@ class ServiceTemplateIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('description',)
@register_search @register_search
@ -143,6 +156,7 @@ class VLANIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('site', 'group', 'tenant', 'status', 'role', 'description')
@register_search @register_search
@ -154,6 +168,7 @@ class VLANGroupIndex(SearchIndex):
('description', 500), ('description', 500),
('max_vid', 2000), ('max_vid', 2000),
) )
display_attrs = ('scope_type', 'min_vid', 'max_vid', 'description')
@register_search @register_search
@ -165,3 +180,4 @@ class VRFIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('rd', 'tenant', 'description')

View File

@ -33,10 +33,12 @@ class SearchIndex:
category: The label of the group under which this indexer is categorized (for form field display). If none, category: The label of the group under which this indexer is categorized (for form field display). If none,
the name of the model's app will be used. the name of the model's app will be used.
fields: An iterable of two-tuples defining the model fields to be indexed and the weight associated with each. fields: An iterable of two-tuples defining the model fields to be indexed and the weight associated with each.
display_attrs: An iterable of additional object attributes to include when displaying search results.
""" """
model = None model = None
category = None category = None
fields = () fields = ()
display_attrs = ()
@staticmethod @staticmethod
def get_field_type(instance, field_name): def get_field_type(instance, field_name):

View File

@ -3,7 +3,8 @@ from collections import defaultdict
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.db.models import F, Window, Q from django.db.models import F, Window, Q, prefetch_related_objects
from django.db.models.fields.related import ForeignKey
from django.db.models.functions import window from django.db.models.functions import window
from django.db.models.signals import post_delete, post_save from django.db.models.signals import post_delete, post_save
from django.utils.module_loading import import_string from django.utils.module_loading import import_string
@ -13,7 +14,7 @@ from netaddr.core import AddrFormatError
from extras.models import CachedValue, CustomField from extras.models import CachedValue, CustomField
from netbox.registry import registry from netbox.registry import registry
from utilities.querysets import RestrictedPrefetch from utilities.querysets import RestrictedPrefetch
from utilities.utils import title from utilities.utils import content_type_identifier, title
from . import FieldTypes, LookupTypes, get_indexer from . import FieldTypes, LookupTypes, get_indexer
DEFAULT_LOOKUP_TYPE = LookupTypes.PARTIAL DEFAULT_LOOKUP_TYPE = LookupTypes.PARTIAL
@ -103,17 +104,17 @@ class CachedValueSearchBackend(SearchBackend):
def search(self, value, user=None, object_types=None, lookup=DEFAULT_LOOKUP_TYPE): def search(self, value, user=None, object_types=None, lookup=DEFAULT_LOOKUP_TYPE):
# Build the filter used to find relevant CachedValue records
query_filter = Q(**{f'value__{lookup}': value}) query_filter = Q(**{f'value__{lookup}': value})
if object_types: if object_types:
# Limit results by object type
query_filter &= Q(object_type__in=object_types) query_filter &= Q(object_type__in=object_types)
if lookup in (LookupTypes.STARTSWITH, LookupTypes.ENDSWITH): if lookup in (LookupTypes.STARTSWITH, LookupTypes.ENDSWITH):
# Partial string matches are valid only on string values # "Starts/ends with" matches are valid only on string values
query_filter &= Q(type=FieldTypes.STRING) query_filter &= Q(type=FieldTypes.STRING)
elif lookup == LookupTypes.PARTIAL:
if lookup == LookupTypes.PARTIAL:
try: try:
# If the value looks like an IP address, add an extra match for CIDR values
address = str(netaddr.IPNetwork(value.strip()).cidr) address = str(netaddr.IPNetwork(value.strip()).cidr)
query_filter |= Q(type=FieldTypes.CIDR) & Q(value__net_contains_or_equals=address) query_filter |= Q(type=FieldTypes.CIDR) & Q(value__net_contains_or_equals=address)
except (AddrFormatError, ValueError): except (AddrFormatError, ValueError):
@ -129,6 +130,12 @@ class CachedValueSearchBackend(SearchBackend):
) )
)[:MAX_RESULTS] )[:MAX_RESULTS]
# Gather all ContentTypes present in the search results (used for prefetching related
# objects). This must be done before generating the final results list, which returns
# a RawQuerySet.
content_type_ids = set(queryset.values_list('object_type', flat=True))
content_types = ContentType.objects.filter(pk__in=content_type_ids)
# Construct a Prefetch to pre-fetch only those related objects for which the # Construct a Prefetch to pre-fetch only those related objects for which the
# user has permission to view. # user has permission to view.
if user: if user:
@ -144,12 +151,34 @@ class CachedValueSearchBackend(SearchBackend):
params params
) )
# Iterate through each ContentType represented in the search results and prefetch any
# related objects necessary to render the prescribed display attributes (display_attrs).
for ct in content_types:
model = ct.model_class()
indexer = registry['search'].get(content_type_identifier(ct))
if not (display_attrs := getattr(indexer, 'display_attrs', None)):
continue
# Add ForeignKey fields to prefetch list
prefetch_fields = []
for attr in display_attrs:
field = model._meta.get_field(attr)
if type(field) is ForeignKey:
prefetch_fields.append(f'object__{attr}')
# Compile a list of all CachedValues referencing this object type, and prefetch
# any related objects
if prefetch_fields:
objects = [r for r in results if r.object_type == ct]
prefetch_related_objects(objects, *prefetch_fields)
# Omit any results pertaining to an object the user does not have permission to view # Omit any results pertaining to an object the user does not have permission to view
ret = [] ret = []
for r in results: for r in results:
if r.object is not None: if r.object is not None:
r.name = str(r.object) r.name = str(r.object)
ret.append(r) ret.append(r)
return ret return ret
def cache(self, instances, indexer=None, remove_existing=True): def cache(self, instances, indexer=None, remove_existing=True):

View File

@ -0,0 +1,14 @@
from netbox.registry import registry
from utilities.utils import content_type_identifier
__all__ = (
'get_indexer',
)
def get_indexer(content_type):
"""
Return the registered search indexer for the given ContentType.
"""
ct_identifier = content_type_identifier(content_type)
return registry['search'].get(ct_identifier)

View File

@ -15,6 +15,7 @@ from extras.choices import CustomFieldVisibilityChoices
from netbox.tables import columns from netbox.tables import columns
from utilities.paginator import EnhancedPaginator, get_paginate_count from utilities.paginator import EnhancedPaginator, get_paginate_count
from utilities.utils import get_viewname, highlight_string, title from utilities.utils import get_viewname, highlight_string, title
from .template_code import *
__all__ = ( __all__ = (
'BaseTable', 'BaseTable',
@ -236,6 +237,10 @@ class SearchTable(tables.Table):
value = tables.Column( value = tables.Column(
verbose_name=_('Value'), verbose_name=_('Value'),
) )
attrs = columns.TemplateColumn(
template_code=SEARCH_RESULT_ATTRS,
verbose_name=_('Attributes')
)
trim_length = 30 trim_length = 30

View File

@ -0,0 +1,18 @@
SEARCH_RESULT_ATTRS = """
{% for name, value in record.display_attrs.items %}
<span class="badge bg-secondary"
{% if value|length > 40 %} data-bs-toggle="tooltip" data-bs-placement="bottom" title="{{ value }}"{% endif %}
>
{{ name|bettertitle }}:
{% with url=value.get_absolute_url %}
{% if url %}<a href="url">{% endif %}
{% if value|length > 40 %}
{{ value|truncatechars:"40" }}
{% else %}
{{ value }}
{% endif %}
{% if url %}</a>{% endif %}
{% endwith %}
</span>
{% endfor %}
"""

View File

@ -15,6 +15,7 @@ class ContactIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('group', 'title', 'phone', 'email', 'description')
@register_search @register_search
@ -25,6 +26,7 @@ class ContactGroupIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)
@register_search @register_search
@ -35,6 +37,7 @@ class ContactRoleIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)
@register_search @register_search
@ -46,6 +49,7 @@ class TenantIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('group', 'description')
@register_search @register_search
@ -56,3 +60,4 @@ class TenantGroupIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)

View File

@ -10,6 +10,7 @@ class ClusterIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('type', 'group', 'status', 'tenant', 'site', 'description')
@register_search @register_search
@ -20,6 +21,7 @@ class ClusterGroupIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)
@register_search @register_search
@ -30,6 +32,7 @@ class ClusterTypeIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)
@register_search @register_search
@ -40,6 +43,7 @@ class VirtualMachineIndex(SearchIndex):
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('site', 'cluster', 'device', 'tenant', 'platform', 'status', 'role', 'description')
@register_search @register_search
@ -51,3 +55,4 @@ class VMInterfaceIndex(SearchIndex):
('description', 500), ('description', 500),
('mtu', 2000), ('mtu', 2000),
) )
display_attrs = ('virtual_machine', 'description')

View File

@ -11,6 +11,7 @@ class WirelessLANIndex(SearchIndex):
('auth_psk', 2000), ('auth_psk', 2000),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('group', 'status', 'vlan', 'tenant', 'description')
@register_search @register_search
@ -21,6 +22,7 @@ class WirelessLANGroupIndex(SearchIndex):
('slug', 110), ('slug', 110),
('description', 500), ('description', 500),
) )
display_attrs = ('description',)
@register_search @register_search
@ -32,3 +34,4 @@ class WirelessLinkIndex(SearchIndex):
('auth_psk', 2000), ('auth_psk', 2000),
('comments', 5000), ('comments', 5000),
) )
display_attrs = ('status', 'tenant', 'description')