Skip to content

Commit 3d20276

Browse files
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
1 parent 2562c87 commit 3d20276

File tree

15 files changed

+165
-7
lines changed

15 files changed

+165
-7
lines changed

docs/development/search.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class MyModelIndex(SearchIndex):
1717
('description', 500),
1818
('comments', 5000),
1919
)
20+
display_attrs = ('site', 'device', 'status', 'description')
2021
```
2122

2223
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.

docs/plugins/development/search.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ class MyModelIndex(SearchIndex):
1414
('description', 500),
1515
('comments', 5000),
1616
)
17+
display_attrs = ('site', 'device', 'status', 'description')
1718
```
1819

20+
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.
21+
1922
To register one or more indexes with NetBox, define a list named `indexes` at the end of this file:
2023

2124
```python

netbox/circuits/search.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class CircuitIndex(SearchIndex):
1010
('description', 500),
1111
('comments', 5000),
1212
)
13+
display_attrs = ('provider', 'provider_account', 'type', 'status', 'tenant', 'description')
1314

1415

1516
@register_search
@@ -22,6 +23,7 @@ class CircuitTerminationIndex(SearchIndex):
2223
('port_speed', 2000),
2324
('upstream_speed', 2000),
2425
)
26+
display_attrs = ('circuit', 'site', 'provider_network', 'description')
2527

2628

2729
@register_search
@@ -32,6 +34,7 @@ class CircuitTypeIndex(SearchIndex):
3234
('slug', 110),
3335
('description', 500),
3436
)
37+
display_attrs = ('description',)
3538

3639

3740
@register_search
@@ -42,6 +45,7 @@ class ProviderIndex(SearchIndex):
4245
('description', 500),
4346
('comments', 5000),
4447
)
48+
display_attrs = ('description',)
4549

4650

4751
class ProviderAccountIndex(SearchIndex):
@@ -51,6 +55,7 @@ class ProviderAccountIndex(SearchIndex):
5155
('account', 200),
5256
('comments', 5000),
5357
)
58+
display_attrs = ('provider', 'account', 'description')
5459

5560

5661
@register_search
@@ -62,3 +67,4 @@ class ProviderNetworkIndex(SearchIndex):
6267
('description', 500),
6368
('comments', 5000),
6469
)
70+
display_attrs = ('provider', 'service_id', 'description')

netbox/core/search.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class DataSourceIndex(SearchIndex):
1111
('description', 500),
1212
('comments', 5000),
1313
)
14+
display_attrs = ('type', 'status', 'description')
1415

1516

1617
@register_search

netbox/dcim/search.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class CableIndex(SearchIndex):
1010
('description', 500),
1111
('comments', 5000),
1212
)
13+
display_attrs = ('type', 'status', 'tenant', 'label', 'description')
1314

1415

1516
@register_search
@@ -21,6 +22,7 @@ class ConsolePortIndex(SearchIndex):
2122
('description', 500),
2223
('speed', 2000),
2324
)
25+
display_attrs = ('device', 'label', 'description')
2426

2527

2628
@register_search
@@ -32,6 +34,7 @@ class ConsoleServerPortIndex(SearchIndex):
3234
('description', 500),
3335
('speed', 2000),
3436
)
37+
display_attrs = ('device', 'label', 'description')
3538

3639

3740
@register_search
@@ -44,6 +47,9 @@ class DeviceIndex(SearchIndex):
4447
('description', 500),
4548
('comments', 5000),
4649
)
50+
display_attrs = (
51+
'site', 'location', 'rack', 'device_type', 'role', 'tenant', 'platform', 'serial', 'asset_tag', 'description',
52+
)
4753

4854

4955
@register_search
@@ -54,6 +60,7 @@ class DeviceBayIndex(SearchIndex):
5460
('label', 200),
5561
('description', 500),
5662
)
63+
display_attrs = ('device', 'label', 'description')
5764

5865

5966
@register_search
@@ -64,6 +71,7 @@ class DeviceRoleIndex(SearchIndex):
6471
('slug', 110),
6572
('description', 500),
6673
)
74+
display_attrs = ('description',)
6775

6876

6977
@register_search
@@ -75,6 +83,7 @@ class DeviceTypeIndex(SearchIndex):
7583
('description', 500),
7684
('comments', 5000),
7785
)
86+
display_attrs = ('manufacturer', 'part_number', 'description')
7887

7988

8089
@register_search
@@ -85,6 +94,7 @@ class FrontPortIndex(SearchIndex):
8594
('label', 200),
8695
('description', 500),
8796
)
97+
display_attrs = ('device', 'label', 'description')
8898

8999

90100
@register_search
@@ -99,6 +109,7 @@ class InterfaceIndex(SearchIndex):
99109
('mtu', 2000),
100110
('speed', 2000),
101111
)
112+
display_attrs = ('device', 'label', 'description')
102113

103114

104115
@register_search
@@ -112,6 +123,7 @@ class InventoryItemIndex(SearchIndex):
112123
('description', 500),
113124
('part_id', 2000),
114125
)
126+
display_attrs = ('device', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description')
115127

116128

117129
@register_search
@@ -122,6 +134,7 @@ class LocationIndex(SearchIndex):
122134
('slug', 110),
123135
('description', 500),
124136
)
137+
display_attrs = ('site', 'status', 'tenant', 'description')
125138

126139

127140
@register_search
@@ -132,6 +145,7 @@ class ManufacturerIndex(SearchIndex):
132145
('slug', 110),
133146
('description', 500),
134147
)
148+
display_attrs = ('description',)
135149

136150

137151
@register_search
@@ -143,6 +157,7 @@ class ModuleIndex(SearchIndex):
143157
('description', 500),
144158
('comments', 5000),
145159
)
160+
display_attrs = ('device', 'module_bay', 'module_type', 'status', 'serial', 'asset_tag', 'description')
146161

147162

148163
@register_search
@@ -153,6 +168,7 @@ class ModuleBayIndex(SearchIndex):
153168
('label', 200),
154169
('description', 500),
155170
)
171+
display_attrs = ('device', 'label', 'position', 'description')
156172

157173

158174
@register_search
@@ -164,6 +180,7 @@ class ModuleTypeIndex(SearchIndex):
164180
('description', 500),
165181
('comments', 5000),
166182
)
183+
display_attrs = ('manufacturer', 'model', 'part_number', 'description')
167184

168185

169186
@register_search
@@ -174,6 +191,7 @@ class PlatformIndex(SearchIndex):
174191
('slug', 110),
175192
('description', 500),
176193
)
194+
display_attrs = ('manufacturer', 'description')
177195

178196

179197
@register_search
@@ -184,6 +202,7 @@ class PowerFeedIndex(SearchIndex):
184202
('description', 500),
185203
('comments', 5000),
186204
)
205+
display_attrs = ('power_panel', 'rack', 'status', 'description')
187206

188207

189208
@register_search
@@ -194,6 +213,7 @@ class PowerOutletIndex(SearchIndex):
194213
('label', 200),
195214
('description', 500),
196215
)
216+
display_attrs = ('device', 'label', 'description')
197217

198218

199219
@register_search
@@ -204,6 +224,7 @@ class PowerPanelIndex(SearchIndex):
204224
('description', 500),
205225
('comments', 5000),
206226
)
227+
display_attrs = ('site', 'location', 'description')
207228

208229

209230
@register_search
@@ -216,6 +237,7 @@ class PowerPortIndex(SearchIndex):
216237
('maximum_draw', 2000),
217238
('allocated_draw', 2000),
218239
)
240+
display_attrs = ('device', 'label', 'description')
219241

220242

221243
@register_search
@@ -229,6 +251,7 @@ class RackIndex(SearchIndex):
229251
('description', 500),
230252
('comments', 5000),
231253
)
254+
display_attrs = ('site', 'location', 'facility_id', 'tenant', 'status', 'role', 'description')
232255

233256

234257
@register_search
@@ -238,6 +261,7 @@ class RackReservationIndex(SearchIndex):
238261
('description', 500),
239262
('comments', 5000),
240263
)
264+
display_attrs = ('rack', 'tenant', 'user', 'description')
241265

242266

243267
@register_search
@@ -248,6 +272,7 @@ class RackRoleIndex(SearchIndex):
248272
('slug', 110),
249273
('description', 500),
250274
)
275+
display_attrs = ('device', 'label', 'description',)
251276

252277

253278
@register_search
@@ -258,6 +283,7 @@ class RearPortIndex(SearchIndex):
258283
('label', 200),
259284
('description', 500),
260285
)
286+
display_attrs = ('device', 'label', 'description')
261287

262288

263289
@register_search
@@ -268,6 +294,7 @@ class RegionIndex(SearchIndex):
268294
('slug', 110),
269295
('description', 500),
270296
)
297+
display_attrs = ('parent', 'description')
271298

272299

273300
@register_search
@@ -282,6 +309,7 @@ class SiteIndex(SearchIndex):
282309
('shipping_address', 2000),
283310
('comments', 5000),
284311
)
312+
display_attrs = ('region', 'group', 'status', 'description')
285313

286314

287315
@register_search
@@ -292,6 +320,7 @@ class SiteGroupIndex(SearchIndex):
292320
('slug', 110),
293321
('description', 500),
294322
)
323+
display_attrs = ('parent', 'description')
295324

296325

297326
@register_search
@@ -303,6 +332,7 @@ class VirtualChassisIndex(SearchIndex):
303332
('description', 500),
304333
('comments', 5000),
305334
)
335+
display_attrs = ('master', 'domain', 'description')
306336

307337

308338
@register_search
@@ -314,3 +344,4 @@ class VirtualDeviceContextIndex(SearchIndex):
314344
('description', 500),
315345
('comments', 5000),
316346
)
347+
display_attrs = ('device', 'status', 'identifier', 'description')

netbox/extras/models/search.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
from django.db import models
55
from django.utils.translation import gettext_lazy as _
66

7+
from netbox.search.utils import get_indexer
8+
from netbox.registry import registry
79
from utilities.fields import RestrictedGenericForeignKey
10+
from utilities.utils import content_type_identifier
811
from ..fields import CachedValueField
912

1013
__all__ = (
@@ -58,3 +61,19 @@ class Meta:
5861

5962
def __str__(self):
6063
return f'{self.object_type} {self.object_id}: {self.field}={self.value}'
64+
65+
@property
66+
def display_attrs(self):
67+
"""
68+
Render any display attributes associated with this search result.
69+
"""
70+
indexer = get_indexer(self.object_type)
71+
attrs = {}
72+
for attr in indexer.display_attrs:
73+
name = self.object._meta.get_field(attr).verbose_name
74+
if value := getattr(self.object, attr):
75+
if display_func := getattr(self.object, f'get_{attr}_display', None):
76+
attrs[name] = display_func()
77+
else:
78+
attrs[name] = value
79+
return attrs

0 commit comments

Comments
 (0)