2011-06-17 29 views
18

Tengo una pequeña aplicación que permite a un usuario calificar un video.Django - save() actualización en clave duplicada

El usuario puede calificar solo una vez. Así que he definido la singularidad en el modelo.

Pero debería poder cambiar su velocidad. Así que la save() debe actualizar el duplicado clave

class VideoRate(models.Model): 
    """Users can Rate each Video on the criterias defined for the topic""" 
    user = models.ForeignKey(User) 
    video = models.ForeignKey(VideoFile) 
    crit = models.ForeignKey(VideoCrit) 
    rate = models.DecimalField(max_digits=2, decimal_places=1, choices=RATE_CHOICES) 
    class Meta: 
    unique_together = (('user', 'video', 'crit'),) 
    verbose_name = 'Video Rating' 

Si

rate = VideoRate(user_id=1, video_id=1, crit_id=1, rate=2) 
rate.save() 

Ha ahorro de la calificación, pero si

rate = VideoRate(user_id=1, video_id=1, crit_id=1, rate=3) 
rate.save() 

consigo el error normal de

IntegrityError: (1062, "Duplicate entry '1-1-1' for key 'user_id'") 

Incluso si uso force_update=True (ya que se basa únicamente en las claves principales)

¿Hay alguna forma de actualizar la clasificación si ya existe sin tener que verificar datos antes?

Respuesta

28

Para actualizar una calificación existente, realmente debe tener la que desea actualizar. Si conoces puede no existir el objeto, utilice get_or_create:

rate, created = VideoRate.objects.get_or_create(user_id=1, video_id=1, crit_id=1) 
rate.rate = 2 
rate.save() 

Puede corto cortar el proceso mediante el uso de update():

VideoRate.objects.filter(user_id=1, video_id=1, crit_id=1).update(rate=2) 

Pero este error de forma silenciosa si la calificación no existe - se no creará uno.

+0

+1: La primera opción hará 2 o 3 consultas, mientras que la segunda hará 1. – sdolan

+0

Parece que no está mal. ¿Quieres decir que Django no puede realizar un 'INSERT INTO ... ON DUPLICATE KEY UPDATE ...'? –

+3

No, porque esa es una extensión específica de MySQL, y Django funciona con una variedad de bases de datos. –

7

Primero, debe verificar si la clasificación existe. Por lo que puede o bien utilizar lo Daniel Roseman dijo o utilizar existe, pero no se puede resolver esto con una simple actualización desde la actualización no crean nuevos registros ...

rating = 2 
rate, created = VideoRate.objects.get_or_create(user_id=1, video_id=1, crit_id=1, 
    defaults={'rate':rating})#if create, also save the rate infdormation 

if not created:# update 
    rate.rate = rating 
    rate.save() 

Puede utilizar los valores predeterminados para pasar exrta argumentos, por lo que si se trata de un inserto , ficha base de datos se crea con toda la información requerida y que no es necesario actualizar de nuevo ...

Documentation

Actualización: Esta respuesta es bastante antigua al igual que la pregunta. Como @peterthomassen mencionar, Django ahora tiene update_or_create() método

+0

La palabra clave 'defaults' también es muy interesante –

+1

Los valores del argumento' defaults' también se usan para actualizar en el caso donde el objeto no necesita ser creado en la base de datos, ver https://docs.djangoproject.com /en/1.11/ref/models/querysets/#update-or-create. En consecuencia, la parte 'si' de tu código no es operativa. – peterthomassen

+0

@peterthomassen gracias por la notificación. Actualizado la respuesta. – FallenAngel

Cuestiones relacionadas