1414from .models import ConfigRevision , CustomField , ObjectChange
1515from .webhooks import enqueue_object , get_snapshots , serialize_for_webhook
1616
17+
1718#
1819# Change logging/webhooks
1920#
2223clear_webhooks = Signal ()
2324
2425
26+ def is_same_object (instance , webhook_data , request_id ):
27+ """
28+ Compare the given instance to the most recent queued webhook object, returning True
29+ if they match. This check is used to avoid creating duplicate webhook entries.
30+ """
31+ return (
32+ ContentType .objects .get_for_model (instance ) == webhook_data ['content_type' ] and
33+ instance .pk == webhook_data ['object_id' ] and
34+ request_id == webhook_data ['request_id' ]
35+ )
36+
37+
38+ @receiver ((post_save , m2m_changed ))
2539def handle_changed_object (sender , instance , ** kwargs ):
2640 """
2741 Fires when an object is created or updated.
2842 """
43+ m2m_changed = False
44+
2945 if not hasattr (instance , 'to_objectchange' ):
3046 return
3147
48+ # Get the current request, or bail if not set
3249 request = current_request .get ()
33- m2m_changed = False
34-
35- def is_same_object (instance , webhook_data ):
36- return (
37- ContentType .objects .get_for_model (instance ) == webhook_data ['content_type' ] and
38- instance .pk == webhook_data ['object_id' ] and
39- request .id == webhook_data ['request_id' ]
40- )
50+ if request is None :
51+ return
4152
4253 # Determine the type of change being made
4354 if kwargs .get ('created' ):
@@ -69,7 +80,7 @@ def is_same_object(instance, webhook_data):
6980
7081 # If this is an M2M change, update the previously queued webhook (from post_save)
7182 queue = webhooks_queue .get ()
72- if m2m_changed and queue and is_same_object (instance , queue [- 1 ]):
83+ if m2m_changed and queue and is_same_object (instance , queue [- 1 ], request . id ):
7384 instance .refresh_from_db () # Ensure that we're working with fresh M2M assignments
7485 queue [- 1 ]['data' ] = serialize_for_webhook (instance )
7586 queue [- 1 ]['snapshots' ]['postchange' ] = get_snapshots (instance , action )['postchange' ]
@@ -84,14 +95,18 @@ def is_same_object(instance, webhook_data):
8495 model_updates .labels (instance ._meta .model_name ).inc ()
8596
8697
98+ @receiver (pre_delete )
8799def handle_deleted_object (sender , instance , ** kwargs ):
88100 """
89101 Fires when an object is deleted.
90102 """
91103 if not hasattr (instance , 'to_objectchange' ):
92104 return
93105
106+ # Get the current request, or bail if not set
94107 request = current_request .get ()
108+ if request is None :
109+ return
95110
96111 # Record an ObjectChange if applicable
97112 if hasattr (instance , 'to_objectchange' ):
@@ -109,6 +124,7 @@ def handle_deleted_object(sender, instance, **kwargs):
109124 model_deletes .labels (instance ._meta .model_name ).inc ()
110125
111126
127+ @receiver (clear_webhooks )
112128def clear_webhook_queue (sender , ** kwargs ):
113129 """
114130 Delete any queued webhooks (e.g. because of an aborted bulk transaction)
0 commit comments