Fixed #20944: Ensure cached scope fields stay consistent when Region, Site, or Location changes (#20986)

This commit is contained in:
Prince Kumar
2025-12-22 20:18:43 +05:30
committed by GitHub
parent 83ee4fb593
commit e5a975176d

View File

@@ -1,13 +1,15 @@
import logging import logging
from django.db.models.signals import post_save, post_delete from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver from django.dispatch import receiver
from dcim.choices import CableEndChoices, LinkStatusChoices from dcim.choices import CableEndChoices, LinkStatusChoices
from virtualization.models import VMInterface from ipam.models import Prefix
from virtualization.models import Cluster, VMInterface
from wireless.models import WirelessLAN
from .models import ( from .models import (
Cable, CablePath, CableTermination, ConsolePort, ConsoleServerPort, Device, DeviceBay, FrontPort, Interface, Cable, CablePath, CableTermination, ConsolePort, ConsoleServerPort, Device, DeviceBay, FrontPort, Interface,
InventoryItem, ModuleBay, PathEndpoint, PowerOutlet, PowerPanel, PowerPort, Rack, RearPort, Location, InventoryItem, Location, ModuleBay, PathEndpoint, PowerOutlet, PowerPanel, PowerPort, Rack, RearPort, Site,
VirtualChassis, VirtualChassis,
) )
from .models.cables import trace_paths from .models.cables import trace_paths
@@ -180,3 +182,40 @@ def update_mac_address_interface(instance, created, raw, **kwargs):
if created and not raw and instance.primary_mac_address: if created and not raw and instance.primary_mac_address:
instance.primary_mac_address.assigned_object = instance instance.primary_mac_address.assigned_object = instance
instance.primary_mac_address.save() instance.primary_mac_address.save()
@receiver(post_save, sender=Location)
@receiver(post_save, sender=Site)
def sync_cached_scope_fields(instance, created, **kwargs):
"""
Rebuild cached scope fields for all CachedScopeMixin-based models
affected by a change in a Region, SiteGroup, Site, or Location.
This method is safe to run for objects created in the past and does
not rely on incremental updates. Cached fields are recomputed from
authoritative relationships.
"""
if created:
return
if isinstance(instance, Location):
filters = {'_location': instance}
elif isinstance(instance, Site):
filters = {'_site': instance}
else:
return
# These models are explicitly listed because they all subclass CachedScopeMixin
# and therefore require their cached scope fields to be recomputed.
for model in (Prefix, Cluster, WirelessLAN):
qs = model.objects.filter(**filters)
for obj in qs.only('id'):
# Recompute cache using the same logic as save()
obj.cache_related_objects()
obj.save(update_fields=[
'_location',
'_site',
'_site_group',
'_region',
])