fix(circuits): Clear Circuit Termination cache on change

Move cache update logic from signal to model save method and track
original values to properly clear old cache when circuit_id or term_side
changes. Add comprehensive tests for all cache update scenarios.

Fixes #21686
This commit is contained in:
Martin Hauser
2026-03-17 17:54:39 +01:00
committed by Jeremy Stretch
parent 66f6b2b6f9
commit 3ededeb0e7
3 changed files with 183 additions and 11 deletions

View File

@@ -347,6 +347,13 @@ class CircuitTermination(
verbose_name = _('circuit termination')
verbose_name_plural = _('circuit terminations')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Cache original values to detect changes
self._orig_circuit_id = self.__dict__.get('circuit_id')
self._orig_term_side = self.__dict__.get('term_side')
def __str__(self):
return f'{self.circuit}: Termination {self.term_side}'
@@ -360,11 +367,39 @@ class CircuitTermination(
raise ValidationError(_("A circuit termination must attach to a terminating object."))
def save(self, *args, **kwargs):
is_new = self._state.adding
update_fields = kwargs.get('update_fields')
# Only consider circuit/term_side changes if those fields
# are actually being persisted
if update_fields is not None:
tracking_relevant = 'circuit' in update_fields or 'term_side' in update_fields
else:
tracking_relevant = True
circuit_changed = tracking_relevant and self._orig_circuit_id and self._orig_circuit_id != self.circuit_id
term_side_changed = tracking_relevant and self._orig_term_side and self._orig_term_side != self.term_side
# Cache objects associated with the terminating object (for filtering)
self.cache_related_objects()
super().save(*args, **kwargs)
# Clear the old termination reference if circuit or term_side changed
if circuit_changed or term_side_changed:
old_termination_name = f'termination_{self._orig_term_side.lower()}'
Circuit.objects.filter(pk=self._orig_circuit_id).update(**{old_termination_name: None})
# Update the cache if this is a new termination or circuit/term_side changed
if is_new or circuit_changed or term_side_changed:
# Update the new circuit's termination reference
termination_name = f'termination_{self.term_side.lower()}'
Circuit.objects.filter(pk=self.circuit_id).update(**{termination_name: self.pk})
# Update cached values for subsequent saves
self._orig_circuit_id = self.circuit_id
self._orig_term_side = self.term_side
def cache_related_objects(self):
self._provider_network = self._region = self._site_group = self._site = self._location = None
if self.termination_type: