2011-04-07 17 views
26

Quiero hacer una desnormalización de datos para un mejor rendimiento, y poner una suma de votos mi blog recibe dentro de un modelo de Post:Django: Cómo acceder Instancia original (sin modificar), en señal de post_save

class Post(models.Model): 
    """ Blog entry """ 
    author   = models.ForeignKey(User) 
    title   = models.CharField(max_length=255) 
    text   = models.TextField() 
    rating   = models.IntegerField(default=0) # here is the sum of votes! 

class Vote(models.Model): 
    """ Vote for blog entry """ 
    post   = models.ForeignKey(Post) 
    voter   = models.ForeignKey(User) 
    value   = models.IntegerField() 

Por supuesto, Necesito mantener el valor Post.rating actual. Nornally me gustaría utilizar la base de datos disparadores para eso, pero ahora que he decidido hacer una señal post_save (para reducir el tiempo de proceso de base de datos):

# vote was saved 
@receiver(post_save, sender=Vote) 
def update_post_votes(sender, instance, created, **kwargs): 
    """ Update post rating """ 
    if created: 
     instance.post.rating += instance.value 
     instance.post.save() 
    else: 
     # if vote was updated, we need to remove the old vote value and add the new one 
     # but how...? 

¿Cómo puedo acceder al valor de la instancia antes de que se salvó? En los desencadenadores de base de datos, tendría OLD y NEW predefinidos para esto, pero ¿hay algo como esto en las señales post_save?

ACTUALIZACIÓN

La solución basada en la respuesta de Mark:

# vote was saved 
@receiver(pre_save, sender=Vote) 
def update_post_votes_on_save(sender, instance, **kwargs): 
    """ Update post rating """ 
    # if vote is being updated, then we must remove previous value first 
    if instance.id: 
     old_vote = Vote.objects.get(pk=instance.id) 
     instance.post.rating -= old_vote.value 
    # now adding the new vote 
    instance.post.rating += instance.value 
    instance.post.save() 

Respuesta

38

creo post_save es demasiado tarde para recuperar la versión sin modificar. Como su nombre lo indica, los datos ya se han escrito en el DB en ese momento. Debería usar pre_save en su lugar. En ese caso, puede recuperar el modelo de db a través de pk: old = Vote.objects.get(pk=instance.pk) y verificar las diferencias en la instancia actual y la instancia anterior.

+0

Gracias, tienes toda la razón. Resulta que cuando se crea instans, no tiene 'id' en la señal pre_save, pero si se trata de actualizaciones, tiene un' id'. Es justo lo que necesitaba, vea la actualización de la pregunta para la solución real. –

Cuestiones relacionadas