2016-04-19 36 views
19

Sto utilizzando il segnale post_save di django per eseguire alcune istruzioni dopo aver salvato il modello.Identifica i campi modificati nel segnale post_save django

class Mode(models.Model): 
    name = models.CharField(max_length=5) 
    mode = models.BooleanField() 


from django.db.models.signals import post_save 
from django.dispatch import receiver 

@receiver(post_save, sender=Mode) 
def post_save(sender, instance, created, **kwargs): 
     # do some stuff 
     pass 

Ora voglio eseguire un'istruzione a seconda che il valore del campo mode è cambiato o meno.

@receiver(post_save, sender=Mode) 
def post_save(sender, instance, created, **kwargs): 
     # if value of `mode` has changed: 
     # then do this 
     # else: 
     # do that 
     pass 

Ho esaminato alcuni thread SOF e un blog ma non sono riuscito a trovare una soluzione. Tutti cercavano di utilizzare il metodo pre_save o il modulo che non sono il mio caso d'uso. https://docs.djangoproject.com/es/1.9/ref/signals/#post-save nei documenti django non menziona un modo diretto per farlo.

Una risposta nel collegamento qui sotto sembra promettente ma non so come usarla. Non sono sicuro se l'ultima versione di django lo supporta o meno, perché ho usato il ipdb per eseguire il debug di questo e ho scoperto che la variabile instance non ha alcun attributo has_changed come indicato nella risposta seguente.

Django: When saving, how can you check if a field has changed?

risposta

13

installarla sul l'__init__ del modello in modo da avere accesso ad esso.

def __init__(self, *args, **kwargs): 
    super(YourModel, self).__init__(*args, **kwargs) 
    self.__original_mode = self.mode 

Ora è possibile eseguire qualcosa di simile:

if instance.mode != instance.__original_mode: 
    # do something useful 
+4

Attenzione. Questo approccio ha degli svantaggi, come discusso a lungo [qui] (http://stackoverflow.com/questions/1355150). In poche parole: non è a prova di gara, e può anche essere sbagliato se hai due istanze python che puntano alla stessa riga db. –

18

Ussually è meglio per ignorare il metodo save rispetto all'utilizzo di segnali.

Da Two scoops of django: "Utilizzare i segnali come ultima risorsa."

Sono d'accordo con @scoopseven risposta sulla memorizzazione nella cache del valore originale su init, ma sovrascrivendo il metodo di salvataggio se è possibile.

class Mode(models.Model): 
    name = models.CharField(max_length=5) 
    mode = models.BooleanField() 
    __original_mode = None 

    def __init__(self, *args, **kwargs): 
     super(Mode, self).__init__(*args, **kwargs) 
     self.__original_mode = self.mode 

    def save(self, force_insert=False, force_update=False, *args, **kwargs): 
     if self.mode != self.__original_mode: 
      # then do this 
     else: 
      # do that 

     super(Mode, self).save(force_insert, force_update, *args, **kwargs) 
     self.__original_mode = self.mode 
+1

Cosa c'è di sbagliato nell'usare i Segnali in Django? Ti aiuta a creare un flusso di lavoro piacevolmente. – Hussain

+3

@Hussain mentre i metodi sono collegati direttamente al modello e puoi vedere il suo comportamento in un posto, i segnali possono essere inseriti in più app diverse e rendere il debug di un incubo e codice meno leggibile. Quindi non si tratta di segnali cattivi, ma i metodi sono più ovvi, e se è possibile, è meglio che tu li segua. –

+0

__original_mode non è sicuro per thread ...... –