@@ -589,9 +589,8 @@ def save(self, *args, **kwargs):
589589 self ._old_backend = None
590590 # emit signals if config is modified and/or if status is changing
591591 if not created and self ._send_config_modified_after_save :
592- self ._send_config_modified_signal (action = self . _config_modified_action )
592+ self ._send_config_modified_signal ()
593593 self ._send_config_modified_after_save = False
594- self ._config_modified_action = "config_changed"
595594 if self ._send_config_status_changed :
596595 self ._send_config_status_changed_signal ()
597596 self ._send_config_status_changed = False
@@ -651,6 +650,14 @@ def update_status_if_checksum_changed(
651650 self ._update_checksum_db (new_checksum = self .checksum_db )
652651 if send_config_modified_signal :
653652 self ._send_config_modified_after_save = True
653+ if save :
654+ # When this method is triggered by changes to Config.templates,
655+ # those changes are applied through the related manager rather
656+ # than via Config.save(). As a result, the model's save()
657+ # method (and thus the automatic "config modified" signal)
658+ # is never invoked. To ensure the signal is still emitted,
659+ # we send it explicitly here.
660+ self ._send_config_modified_signal ()
654661 self .invalidate_checksum_cache ()
655662 return checksum_changed
656663
@@ -695,13 +702,24 @@ def _set_config_modified_timeout_cache(self):
695702 def _delete_config_modified_timeout_cache (self ):
696703 cache .delete (self ._config_modified_timeout_cache_key )
697704
698- def _send_config_modified_signal (self , action ):
705+ def _send_config_modified_signal (self , action = None ):
699706 """
700707 Emits ``config_modified`` signal.
701- Called also by Template when templates of a device are modified
708+
709+ A short-lived cache key (``_CONFIG_MODIFIED_TIMEOUT``)
710+ prevents emitting duplicate signals inside the same logical window;
711+ if that key exists the method returns early without emitting.
712+
713+ Side effects
714+ ------------
715+ - Emits the ``config_modified`` Django signal with contextual data.
716+ - Resets ``_config_modified_action`` back to ``"config_changed"`` so
717+ subsequent calls without an explicit action revert to the default.
718+ - Sets the debouncing cache key to avoid duplicate emissions.
702719 """
703- if cache .get (self ._config_modified_timeout_cache_key ) is not None :
720+ if cache .get (self ._config_modified_timeout_cache_key ):
704721 return
722+ action = action or self ._config_modified_action
705723 assert action in [
706724 "config_changed" ,
707725 "related_template_changed" ,
@@ -721,6 +739,7 @@ def _send_config_modified_signal(self, action):
721739 True ,
722740 timeout = self ._CONFIG_MODIFIED_TIMEOUT ,
723741 )
742+ self ._config_modified_action = "config_changed"
724743
725744 def _send_config_deactivating_signal (self ):
726745 """
0 commit comments