diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index 74fcdc37f..c281e5de2 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -829,13 +829,23 @@ class Device( def clean(self): super().clean() - # Validate site/location combination + # Validate site/location/rack combination + if self.rack and self.site != self.rack.site: + raise ValidationError({ + 'rack': _("Rack {rack} does not belong to site {site}.").format(rack=self.rack, site=self.site), + }) if self.location and self.site != self.location.site: raise ValidationError({ 'location': _( "Location {location} does not belong to site {site}." ).format(location=self.location, site=self.site) }) + if self.rack and self.location and self.rack.location != self.location: + raise ValidationError({ + 'rack': _( + "Rack {rack} does not belong to location {location}." + ).format(rack=self.rack, location=self.location) + }) if self.rack is None: if self.face: @@ -1021,9 +1031,8 @@ class Device( if is_new and not self.platform: self.platform = self.device_type.default_platform - # Inherit site/location from Rack - if self.rack: - self.site = self.rack.site + # Inherit location from Rack if not set + if self.rack and self.rack.location: self.location = self.rack.location super().save(*args, **kwargs) diff --git a/netbox/dcim/tests/test_models.py b/netbox/dcim/tests/test_models.py index 3f1fded65..c4f7b0691 100644 --- a/netbox/dcim/tests/test_models.py +++ b/netbox/dcim/tests/test_models.py @@ -623,9 +623,8 @@ class DeviceTestCase(TestCase): device_type = DeviceType.objects.first() device_role = DeviceRole.objects.first() - # Device should use site and location from rack - device = Device.objects.create(name='device1', rack=rack, device_type=device_type, role=device_role) - self.assertEqual(device.site, site) + # Device should use location from rack + device = Device.objects.create(name='device1', site=site, rack=rack, device_type=device_type, role=device_role) self.assertEqual(device.location, location) def test_device_mismatched_site_cluster(self):