@@ -100,6 +100,15 @@ class AbstractConfig(ChecksumCacheMixin, BaseConfig):
100100 load_kwargs = {"object_pairs_hook" : collections .OrderedDict },
101101 dump_kwargs = {"indent" : 4 },
102102 )
103+ checksum_db = models .CharField (
104+ _ ("database checksum" ),
105+ max_length = 32 ,
106+ blank = True ,
107+ null = True ,
108+ help_text = _ (
109+ "Last known checksum stored in database for optimization purposes."
110+ ),
111+ )
103112
104113 _CHECKSUM_CACHE_TIMEOUT = 60 * 60 * 24 * 30 # 10 days
105114 _config_context_functions = list ()
@@ -265,7 +274,15 @@ def templates_changed(cls, action, instance, **kwargs):
265274 there fore we need to ignore it to avoid emitting signals twice
266275 """
267276 # execute only after a config has been saved or deleted
268- if action not in ["post_add" , "post_remove" ] or instance ._state .adding :
277+ if (
278+ action not in ["post_add" , "post_remove" , "post_clear" ]
279+ or instance ._state .adding
280+ ):
281+ return
282+ if action == "post_clear" :
283+ if hasattr (instance , "backend_instance" ):
284+ del instance .backend_instance
285+ cls .objects .filter (pk = instance .pk ).update (checksum_db = instance .checksum )
269286 return
270287 # use atomic to ensure any code bound to
271288 # be executed via transaction.on_commit
@@ -276,9 +293,9 @@ def templates_changed(cls, action, instance, **kwargs):
276293 if not instance ._just_created :
277294 # sends only config modified signal
278295 instance ._send_config_modified_signal (action = "m2m_templates_changed" )
279- if instance .status != "modified" :
280- # sends both status modified and config modified signals
281- instance . set_status_modified ( send_config_modified_signal = False )
296+ instance .check_and_update_status_if_changed (
297+ send_config_modified_signal = False
298+ )
282299
283300 @classmethod
284301 def manage_vpn_clients (cls , action , instance , pk_set , ** kwargs ):
@@ -538,9 +555,11 @@ def clean(self):
538555
539556 def save (self , * args , ** kwargs ):
540557 created = self ._state .adding
541- # check if config has been modified (so we can emit signals)
542558 if not created :
543559 self ._check_changes ()
560+ if hasattr (self , "backend_instance" ):
561+ del self .backend_instance
562+ self .checksum_db = self .checksum
544563 self ._just_created = created
545564 result = super ().save (* args , ** kwargs )
546565 # add default templates if config has just been created
@@ -579,7 +598,10 @@ def is_deactivated(self):
579598
580599 def _check_changes (self ):
581600 current = self ._meta .model .objects .only (
582- "backend" , "config" , "context" , "status"
601+ "backend" ,
602+ "config" ,
603+ "context" ,
604+ "status" ,
583605 ).get (pk = self .pk )
584606 if self .backend != current .backend :
585607 # storing old backend to send backend change signal after save
@@ -594,6 +616,48 @@ def _check_changes(self):
594616 # regardless of the current status
595617 self ._send_config_modified_after_save = True
596618
619+ def check_and_update_status_if_changed (
620+ self , save = True , send_config_modified_signal = True
621+ ):
622+ """
623+ Helper method to check if configuration has changed based on checksum
624+ comparison and update status accordingly.
625+ """
626+
627+ checksum_changed = self ._should_update_status_based_on_checksum ()
628+ if checksum_changed :
629+ self .checksum_db = self .checksum
630+ if self .status != "modified" :
631+ self .set_status_modified (
632+ save = save ,
633+ send_config_modified_signal = send_config_modified_signal ,
634+ extra_update_fields = ["checksum_db" ],
635+ )
636+ else :
637+ self ._meta .model .objects .filter (pk = self .pk ).update (
638+ checksum_db = self .checksum_db
639+ )
640+ return checksum_changed
641+
642+ def _should_update_status_based_on_checksum (self ):
643+ """
644+ Determines whether the config status should be updated based on
645+ checksum comparison.
646+
647+ Returns True if:
648+ - No checksum_db exists (first time)
649+ - Current checksum differs from checksum_db
650+
651+ Returns False if:
652+ - Current checksum is the same as checksum_db
653+ """
654+ if self .checksum_db is None :
655+ # First time or no database checksum, should update
656+ return True
657+ if hasattr (self , "backend_instance" ):
658+ delattr (self , "backend_instance" )
659+ return self .checksum_db != self .checksum
660+
597661 def _send_config_modified_signal (self , action ):
598662 """
599663 Emits ``config_modified`` signal.
@@ -668,10 +732,12 @@ def _set_status(self, status, save=True, reason=None, extra_update_fields=None):
668732 if save :
669733 self .save (update_fields = update_fields )
670734
671- def set_status_modified (self , save = True , send_config_modified_signal = True ):
735+ def set_status_modified (
736+ self , save = True , send_config_modified_signal = True , extra_update_fields = None
737+ ):
672738 if send_config_modified_signal :
673739 self ._send_config_modified_after_save = True
674- self ._set_status ("modified" , save )
740+ self ._set_status ("modified" , save , extra_update_fields )
675741
676742 def set_status_applied (self , save = True ):
677743 self ._set_status ("applied" , save )
0 commit comments