2010-03-08 9 views

risposta

7

Modifica della risposta di cui sopra ... prendendo la funzione brillante da Dominik Szopa e cambiarla sarà risolvere il change detection rapporto: Usare questo:

def get_changes_between_models(model1, model2, excludes = []): 
    changes = {} 
    for field in model1._meta.fields: 
     if not (field.name in excludes): 
      if field.value_from_object(model1) != field.value_from_object(model2): 
       changes[field.verbose_name] = (field.value_from_object(model1), 
                field.value_from_object(model2)) 
    return changes 

Poi nel codice si può dire (evitare try/tranne che per motivi di prestazioni):

if (self.id): 
    old = MyModel.Objects.get(pk=self.id) 
    changes = get_changes_between_models(self, old) 

    if (changes): 
     # Process based on what is changed. 

Se si esegue questa operazione a livello di "modello", non è possibile salvare la query aggiuntiva. I dati sono già stati modificati dal momento in cui si raggiunge il punto "Salva". Il mio primo post, quindi perdonami se sembro un idiota.

+0

Grazie per il suggerimento su 'Field.value_from_object()'! Apparentemente fornisce un modo coerente di confrontare i valori. Bello! –

+0

Per rendere questa risposta più leggibile, precisa e chiara, cambierei "model1" in "model_instance_1" e "model2" in "model_instance_2". E il nome del metodo dovrebbe forse essere "get_changes_between_model_instances". Non sono sicuro che ci sia un modo migliore nelle versioni più recenti di Django ma sto usando 1.8 attualmente e questa risposta funzionerà per me. – jenniwren

0

Quello che devi fare è ottenere una copia extra dell'oggetto che stai lavorando dal database all'interno del metodo di salvataggio prima di salvarlo completamente. Esempio:

class MyModel(models.Model): 
    field1 = models.CharField(max_length=50) 

    def save(self): 
     if self.id: 
      try: 
       old = MyModel.objects.get(pk=self.id) 
       if old.field1 != self.field1: 
        # Process somehow 
      except MyModel.DoesNotExist: 
       pass 
     super(MyModel, self).save() 
+0

Mi è venuto anche in mente qualcosa di simile, (recupera l'oggetto dal DB prima che venga salvato e confrontalo con la copia che sta per essere salvata) ma vorrei salvare la query aggiuntiva. –

1

Al fine di ottenere le differenze di due istanze del modello, è anche possibile utilizzare questo function. Si confronta con le istanze del modello e restituisce il dizionario delle modifiche.

+0

È utile! Ma sembra che non sia a conoscenza dei campi correlati. Per i miei scopi, aggiungere o eliminare una relazione (uno-a-molti o molti-a-molti) è anche un cambiamento dell'oggetto. –

7

Per evitare di ricerca in più DB, ho modificato il costruttore di ricordare valore iniziale e utilizzare questo metodo Save in seguito:

class Package(models.Model): 
    feedback = models.IntegerField(default = 0, choices = FEEDBACK_CHOICES) 
    feedback_time = models.DateTimeField(null = True) 

    def __init__(self, *args, **kw): 
     super(Package, self).__init__(*args, **kw) 
     self._old_feedback = self.feedback 

    def save(self, force_insert=False, force_update=False, *args, **kwargs): 
     if not force_insert and self.feedback != self._old_feedback: 
      self.feedback_time = datetime.utcnow() 
     return super(Package, self).save(force_insert, force_update, *args, **kwargs) 
+2

Mi sembra che in molti casi questo non faccia quello che vuoi. Ad esempio, all'invio del modulo, un oggetto viene inizializzato dai parametri POST e quindi salvato. Il metodo di salvataggio non troverà una differenza tra i valori del campo iniziale e corrente; ma sono diversi da quelli nel database. –

Problemi correlati