2010-04-16 14 views
1

dire que j'ai:Quel est l'idiome best/proper dans django pour modifier un champ pendant un .save() où vous avez besoin d'une ancienne valeur?

class LogModel(models.Model): 
    message = models.CharField(max_length=512) 

class Assignment(models.Model): 
    someperson = models.ForeignKey(SomeOtherModel) 
    def save(self, *args, **kwargs): 
     super(Assignment, self).save() 
     old_person = #????? 
     LogModel(message="%s is no longer assigned to %s"%(old_person, self).save() 
     LogModel(message="%s is now assigned to %s"%(self.someperson, self).save() 

Mon but est de sauver à LogModel des messages au sujet de qui a été affecté à affectation. Notez que j'ai besoin de connaître l'ancienne valeur presave de ce champ.

J'ai vu du code qui suggère, avant super(). Save(), récupérer l'instance de la base de données via la clé primaire et récupérer l'ancienne valeur à partir de là. Cela pourrait fonctionner, mais c'est un peu brouillon. En outre, j'ai l'intention de finir par séparer ce code de la méthode .save() via des signaux - à savoir pre_save() et post_save(). Essayer d'utiliser la logique ci-dessus (Récupérer à partir de la base de données dans pre_save, rendre l'entrée de journal dans post_save) semble échouer ici, car pre_save et post_save sont deux méthodes distinctes. Peut-être dans pre_save je peux récupérer l'ancienne valeur et la coller sur le modèle en tant qu'attribut? Je me demandais s'il y avait un idiome commun pour cela. Merci.

Répondre

0

Il peut être facilement fait avec signals. Il y a respectivement un signal pre-save et post-save pour chaque modèle Django.

+1

Je le sais, mais vous n'avez pas répondu à la question de conserver l'ancienne valeur entre les deux. Aussi, si faire un autre hit db est vraiment la bonne façon de garder l'ancienne valeur. – MDBGuy

0

Alors je suis venu avec ceci:

class LogModel(models.Model): 
    message = models.CharField(max_length=512) 

class Assignment(models.Model): 
    someperson = models.ForeignKey(SomeOtherModel) 

import weakref 
_save_magic = weakref.WeakKeyDictionary() 

@connect(pre_save, Assignment) 
def Assignment_presave(sender, instance, **kwargs): 
    if instance.pk: 
     _save_magic[instance] = Assignment.objects.get(pk=instance.pk).someperson 

@connect(post_save, Assignment) 
def Assignment_postsave(sender, instance, **kwargs): 
    old = None 
    if instance in _save_magic: 
     old = _save_magic[instance] 
     del _save_magic[instance] 
     LogModel(message="%s is no longer assigned to %s"%(old, self).save() 
    LogModel(message="%s is now assigned to %s"%(instance.someperson, self).save() 

Qu'est-ce que StackOverflow pense? Quelque chose de mieux? Des conseils?

+0

PS: @connect est un décorateur personnalisé qui fait juste signal.connect (f, sender = self.sender) – MDBGuy

1

Quelques mois j'ai trouvé quelque part en ligne une bonne façon de le faire ...

class YourModel(models.Model): 

    def __init__(self, *args, **kwargs): 
     super(YourModel, self).__init__(*args, **kwargs) 
     self.original = {} 
     id = getattr(self, 'id', None) 

     for field in self._meta.fields: 
      if id: 
       self.original[field.name] = getattr(self, field.name, None) 
      else: 
       self.original[field.name] = None 

Fondamentalement, une copie des champs de modèle sont sauvés à self.original. Vous pouvez alors y accéder ailleurs dans le modèle ...

def save(self, *args, **kwargs): 
    if self.original['my_property'] != self.my_property: 
     # ... 
+0

Hm, bonne idée. Merci beaucoup! – MDBGuy