Просмотр исходного кода

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

Prince Kumar 1 месяц назад
Родитель
Сommit
e5a975176d
1 измененных файлов с 42 добавлено и 3 удалено
  1. 42 3
      netbox/dcim/signals.py

+ 42 - 3
netbox/dcim/signals.py

@@ -1,13 +1,15 @@
 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 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 (
     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,
 )
 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:
         instance.primary_mac_address.assigned_object = instance
         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',
+            ])