2011-06-17 150 views
18

我有一个小应用程序,它允许用户评价一个视频。Django - 保存()更新重复密钥

用户只能打分一次。 所以我定义了模型的唯一性。

但他应该能够改变他的速度。 所以save()应该重复键

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' 

更新如果我

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

它节省了评级,但如果我

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

我得到正常的错误

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

即使我使用force_update=True(因为仅基于主键)

有没有更新评级的方法,如果它已经存在,而无需事先检查数据?

回答

28

要更新现有评分,您实际上必须拥有要更新的评分。如果您知道对象可能不存在,使用get_or_create

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

您可以走捷径的过程中通过使用update()

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

但如果评价不存在,这将失败默默 - 它将不会创建一个。

+0

+1:第一个选项会做2或3个查询,而第二个会做1。 – sdolan 2011-06-17 08:00:15

+0

似乎还不错。你的意思是Django不能执行'INSERT INTO ... ON DUPLICATE KEY UPDATE ...'? – 2011-06-17 09:11:51

+3

不,因为这是一个特定于MySQL的扩展,并且Django可以处理一系列数据库。 – 2011-06-17 09:20:48

7

首先,您必须检查评级是否存在。所以,你既可以用什么丹尼尔·罗斯曼说或使用存在,但你不能用一个简单的更新解决了这个,因为更新不创造新的纪录......

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() 

您可以使用默认通过exrta参数,因此,如果它是一个插入,数据库记录将与所有需要的信息来创建,你并不需要更新一次......

Documentation

更新:这个答案就像问题一样古老。至于@peterthomassen提到,Django现在有update_or_create()方法

+0

'defaults'关键字也非常有趣 – 2011-10-07 07:03:01

+1

来自'defaults'参数的值也用于在数据库中不需要创建对象的情况下进行更新,请参阅https://docs.djangoproject.com /en/1.11/ref/models/querysets/#update-or-create。因此,你的代码中的“if”部分是无操作的。 – peterthomassen 2017-09-25 22:05:39

+0

@peterthomassen感谢您的通知。更新了答案。 – FallenAngel 2017-09-26 12:38:38