Arthur пре 1 месец
родитељ
комит
46f7293143
2 измењених фајлова са 13 додато и 5 уклоњено
  1. 8 0
      netbox/core/signals.py
  2. 5 5
      netbox/core/tests/test_signals.py

+ 8 - 0
netbox/core/signals.py

@@ -232,6 +232,14 @@ def handle_deleted_object(sender, instance, **kwargs):
                 # already been recorded, so nulling the FK and saving here would record an
                 # UPDATE ObjectChange *after* the object's DELETE, corrupting the changelog and
                 # breaking branch replay. (Ref: #22270)
+                #
+                # Note this is order-dependent: it only fires once the related object's own
+                # pre_delete has run (adding it to the set). If the cascade happens to delete
+                # this instance *before* the related object, the guard won't trigger and the
+                # related object still gets an UPDATE — but in the harmless UPDATE-then-DELETE
+                # order, not the corrupting DELETE-then-UPDATE order. Fully suppressing it in
+                # every ordering would require the complete deletion set, which isn't available
+                # from a pre_delete signal.
                 if (related_object_type, obj.pk) in _signals_received.pre_delete:
                     continue
                 obj.snapshot()  # Ensure the change record includes the "before" state

+ 5 - 5
netbox/core/tests/test_signals.py

@@ -240,11 +240,11 @@ class HandleDeletedObjectSignalTestCase(TestCase):
                     changed_object_id=member_pk,
                 ).order_by('time', 'pk').values_list('action', flat=True)
             )
-            self.assertIn(ObjectChangeActionChoices.ACTION_DELETE, actions)
-            # The member's final change record must be its deletion, with no trailing update.
-            self.assertEqual(actions[-1], ObjectChangeActionChoices.ACTION_DELETE)
-            delete_index = actions.index(ObjectChangeActionChoices.ACTION_DELETE)
-            self.assertNotIn(ObjectChangeActionChoices.ACTION_UPDATE, actions[delete_index + 1:])
+            # In this ordering the member's pre_delete fires before the LAG's, so the LAG
+            # skips it: the member's only change record for the request is its own deletion.
+            # Pre-fix, a spurious UPDATE was appended *after* this DELETE — assert the exact
+            # sequence so any trailing (or leading) update fails the test.
+            self.assertEqual(actions, [ObjectChangeActionChoices.ACTION_DELETE])
 
 
 class ClearSignalHistorySignalTestCase(TestCase):