delete handling
This commit is contained in:
parent
00ed38771a
commit
325959fe36
|
|
@ -1,4 +1,20 @@
|
|||
from django.apps import AppConfig
|
||||
from django.db.models.signals import pre_delete
|
||||
|
||||
|
||||
def _clear_circuit_termination_pointer(sender, **kwargs):
|
||||
from .models import CircuitTermination
|
||||
from .signals import clear_circuit_termination_pointer
|
||||
|
||||
if sender is CircuitTermination:
|
||||
clear_circuit_termination_pointer(**kwargs)
|
||||
|
||||
|
||||
# This module is imported in populate() phase 1, ahead of the models phase which connects
|
||||
# core.signals.handle_deleted_object. Connecting here records the Circuit pointer clear before the
|
||||
# termination's own DELETE; branch revert replays newest-first and needs the termination restored
|
||||
# before the pointer referencing it. (#23134)
|
||||
pre_delete.connect(_clear_circuit_termination_pointer)
|
||||
|
||||
|
||||
class CircuitsConfig(AppConfig):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from django.db.models.signals import post_delete, post_save, pre_delete
|
||||
from django.db.models.signals import post_delete, post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from dcim.signals import rebuild_paths
|
||||
|
|
@ -17,12 +17,13 @@ def rebuild_cablepaths(instance, raw=False, **kwargs):
|
|||
rebuild_paths([peer_termination])
|
||||
|
||||
|
||||
@receiver(pre_delete, sender=CircuitTermination)
|
||||
def clear_circuit_termination_pointer(instance, using=None, origin=None, **kwargs):
|
||||
"""
|
||||
Clear the parent Circuit's cached `termination_a`/`termination_z` pointer with a change-logged
|
||||
save. on_delete=SET_NULL clears it via a bulk UPDATE, and related_name='+' hides the relation
|
||||
from Circuit._meta.related_objects, so neither path records an ObjectChange. (#23134)
|
||||
|
||||
Connected in CircuitsConfig, not here, so that it precedes handle_deleted_object.
|
||||
"""
|
||||
if not instance.term_side:
|
||||
return
|
||||
|
|
|
|||
|
|
@ -482,14 +482,12 @@ class CircuitTerminationChangeLoggingTestCase(TestCase):
|
|||
self.assertEqual(changes[0].prechange_data['termination_a'], termination_pk)
|
||||
self.assertIsNone(changes[0].postchange_data['termination_a'])
|
||||
|
||||
# core.signals.handle_deleted_object is connected before this app's receiver, so the
|
||||
# DELETE precedes the pointer clear. Replaying in this order relies on the consumer
|
||||
# applying the DELETE through the ORM, where on_delete=SET_NULL clears the pointer, or
|
||||
# on the FK being DEFERRABLE INITIALLY DEFERRED within one transaction.
|
||||
# The pointer clear must precede the DELETE, so that a consumer replaying in reverse
|
||||
# restores the termination before the record which references it
|
||||
termination_delete = self._termination_change(
|
||||
termination_pk, ObjectChangeActionChoices.ACTION_DELETE
|
||||
)
|
||||
self.assertLess(termination_delete.pk, changes[0].pk)
|
||||
self.assertLess(changes[0].pk, termination_delete.pk)
|
||||
|
||||
@tag('regression') # Ref: #23134
|
||||
def test_bulk_deletion_records_circuit_update(self):
|
||||
|
|
|
|||
Loading…
Reference in New Issue