From f113557e810dc52ff3870b48eb87552f6aec4a82 Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Fri, 13 Feb 2026 09:01:11 -0600 Subject: [PATCH] Fixes #21127: Clear _path on interfaces when removed from cable When editing a cable to remove an interface from the B side, the _path field on the removed interface was not being cleared. This caused the interface table to display stale connection info via _path.destinations. Two changes: - Signal handler now clears _path when termination removed from origins - CablePath.delete() clears _path on origins (mirrors save() behavior) --- netbox/dcim/models/cables.py | 10 ++++++++++ netbox/dcim/signals.py | 2 ++ netbox/dcim/tests/test_cablepaths.py | 5 ++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/netbox/dcim/models/cables.py b/netbox/dcim/models/cables.py index e14e20bfb..9835e13f8 100644 --- a/netbox/dcim/models/cables.py +++ b/netbox/dcim/models/cables.py @@ -657,6 +657,16 @@ class CablePath(models.Model): origin_ids = [decompile_path_node(node)[1] for node in self.path[0]] origin_model.objects.filter(pk__in=origin_ids).update(_path=self.pk) + def delete(self, *args, **kwargs): + # Mirror save() - clear _path on origins to prevent stale references + # in table views that render _path.destinations + if self.path: + origin_model = self.origin_type.model_class() + origin_ids = [decompile_path_node(node)[1] for node in self.path[0]] + origin_model.objects.filter(pk__in=origin_ids, _path=self.pk).update(_path=None) + + super().delete(*args, **kwargs) + @property def origin_type(self): if self.path: diff --git a/netbox/dcim/signals.py b/netbox/dcim/signals.py index 97200662b..dd9b7a0a6 100644 --- a/netbox/dcim/signals.py +++ b/netbox/dcim/signals.py @@ -170,6 +170,8 @@ def nullify_connected_endpoints(instance, **kwargs): # Remove the deleted CableTermination if it's one of the path's originating nodes if instance.termination in cablepath.origins: cablepath.origins.remove(instance.termination) + # Clear _path on the removed origin to prevent stale connection display + model.objects.filter(pk=instance.termination_id, _path=cablepath.pk).update(_path=None) cablepath.retrace() diff --git a/netbox/dcim/tests/test_cablepaths.py b/netbox/dcim/tests/test_cablepaths.py index 1bd613e3b..08c807280 100644 --- a/netbox/dcim/tests/test_cablepaths.py +++ b/netbox/dcim/tests/test_cablepaths.py @@ -2806,7 +2806,6 @@ class LegacyCablePathTests(CablePathTestCase): interface2 = Interface.objects.create(device=self.device, name='Interface 2') interface3 = Interface.objects.create(device=self.device, name='Interface 3') - # Create cables 1 cable1 = Cable( a_terminations=[interface1], b_terminations=[interface2, interface3] @@ -2838,6 +2837,10 @@ class LegacyCablePathTests(CablePathTestCase): is_active=True ) + # Verify _path is cleared on removed interface (#21127) + interface3.refresh_from_db() + self.assertPathIsNotSet(interface3) + def test_401_exclude_midspan_devices(self): """ [IF1] --C1-- [FP1][Test Device][RP1] --C2-- [RP2][Test Device][FP2] --C3-- [IF2]