Fixes 17357: Use virtual chassis name as fallback for device (#18710)

This commit is contained in:
Alexander Haase 2025-02-25 16:55:00 +01:00 committed by GitHub
parent 4a4596d5e8
commit bf836c9bc2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 46 additions and 15 deletions

View File

@ -1193,6 +1193,7 @@ class DeviceFilterSet(
return queryset return queryset
return queryset.filter( return queryset.filter(
Q(name__icontains=value) | Q(name__icontains=value) |
Q(virtual_chassis__name__icontains=value) |
Q(serial__icontains=value.strip()) | Q(serial__icontains=value.strip()) |
Q(inventoryitems__serial__icontains=value.strip()) | Q(inventoryitems__serial__icontains=value.strip()) |
Q(asset_tag__icontains=value.strip()) | Q(asset_tag__icontains=value.strip()) |

View File

@ -802,14 +802,10 @@ class Device(
verbose_name_plural = _('devices') verbose_name_plural = _('devices')
def __str__(self): def __str__(self):
if self.name and self.asset_tag: if self.label and self.asset_tag:
return f'{self.name} ({self.asset_tag})' return f'{self.label} ({self.asset_tag})'
elif self.name: elif self.label:
return self.name return self.label
elif self.virtual_chassis and self.asset_tag:
return f'{self.virtual_chassis.name}:{self.vc_position} ({self.asset_tag})'
elif self.virtual_chassis:
return f'{self.virtual_chassis.name}:{self.vc_position} ({self.pk})'
elif self.device_type and self.asset_tag: elif self.device_type and self.asset_tag:
return f'{self.device_type.manufacturer} {self.device_type.model} ({self.asset_tag})' return f'{self.device_type.manufacturer} {self.device_type.model} ({self.asset_tag})'
elif self.device_type: elif self.device_type:
@ -1073,14 +1069,22 @@ class Device(
device.location = self.location device.location = self.location
device.save() device.save()
@property
def label(self):
"""
Return the device name if set; otherwise return a generated name if available.
"""
if self.name:
return self.name
if self.virtual_chassis:
return f'{self.virtual_chassis.name}:{self.vc_position}'
@property @property
def identifier(self): def identifier(self):
""" """
Return the device name if set; otherwise return the Device's primary key as {pk} Return the device name if set; otherwise return the Device's primary key as {pk}
""" """
if self.name is not None: return self.label or '{{{}}}'.format(self.pk)
return self.name
return '{{{}}}'.format(self.pk)
@property @property
def primary_ip(self): def primary_ip(self):

View File

@ -44,6 +44,7 @@ class DeviceIndex(SearchIndex):
('asset_tag', 50), ('asset_tag', 50),
('serial', 60), ('serial', 60),
('name', 100), ('name', 100),
('virtual_chassis', 200),
('description', 500), ('description', 500),
('comments', 5000), ('comments', 5000),
) )

View File

@ -30,10 +30,8 @@ STROKE_RESERVED = '#4d4dff'
def get_device_name(device): def get_device_name(device):
if device.virtual_chassis: if device.label:
name = f'{device.virtual_chassis.name}:{device.vc_position}' name = device.label
elif device.name:
name = device.name
else: else:
name = str(device.device_type) name = str(device.device_type)
if device.devicebay_count: if device.devicebay_count:

View File

@ -143,6 +143,7 @@ class PlatformTable(NetBoxTable):
class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = tables.TemplateColumn( name = tables.TemplateColumn(
verbose_name=_('Name'), verbose_name=_('Name'),
accessor=Accessor('label'),
template_code=DEVICE_LINK, template_code=DEVICE_LINK,
linkify=True linkify=True
) )

View File

@ -590,6 +590,32 @@ class DeviceTestCase(TestCase):
device2.full_clean() device2.full_clean()
device2.save() device2.save()
def test_device_label(self):
device1 = Device(
site=Site.objects.first(),
device_type=DeviceType.objects.first(),
role=DeviceRole.objects.first(),
name=None,
)
self.assertEqual(device1.label, None)
device1.name = 'Test Device 1'
self.assertEqual(device1.label, 'Test Device 1')
virtual_chassis = VirtualChassis.objects.create(name='VC 1')
device2 = Device(
site=Site.objects.first(),
device_type=DeviceType.objects.first(),
role=DeviceRole.objects.first(),
name=None,
virtual_chassis=virtual_chassis,
vc_position=2,
)
self.assertEqual(device2.label, 'VC 1:2')
device2.name = 'Test Device 2'
self.assertEqual(device2.label, 'Test Device 2')
def test_device_mismatched_site_cluster(self): def test_device_mismatched_site_cluster(self):
cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1') cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
Cluster.objects.create(name='Cluster 1', type=cluster_type) Cluster.objects.create(name='Cluster 1', type=cluster_type)