Django Rest Framework:重复键值违反唯一约束

Posted

技术标签:

【中文标题】Django Rest Framework:重复键值违反唯一约束【英文标题】:Django Rest Framework: Duplicate key value violates unique constraint 【发布时间】:2017-11-22 04:45:51 【问题描述】:

我对 Django Rest 框架有疑问。我正在构建的这个应用程序是 Avatar。用户可以更新他/她自己的头像,然后用我定义的路径(/users_id/photoset_id/filename.png)自动保存头像。所以我制作了这样的代码保存功能:

def avatar_file_path(instance, filename):
    ext = filename.split('.')[-1]
    filename = '%s.%s' % (instance.id, ext)
    return "users/%s/avatar/%s_%s" %(instance.user.id, instance.photoset.id, filename)

class Avatar(models.Model):
    user = models.ForeignKey(User, related_name='avatar_set', null=True)
    photoset = models.ForeignKey(PhotoSet, null=True, blank=True)
    primary = models.BooleanField(default=True)
    caption = models.TextField(blank=True, null=True)
    image = models.ImageField(max_length=1024, upload_to=avatar_file_path)
    is_public = models.BooleanField(_('is public'), default=True, help_text=_('Public photographs will be displayed in the default views.'))
    date_uploaded = models.DateTimeField(default=datetime.datetime.now)

    def save(self, force_insert=False, force_update=False, *args, **kwargs):
        # Make one primary Avatar
        if self.primary:
            avatars = Avatar.objects.filter(user=self.user, primary=True).exclude(id=self.id)
            avatars.update(primary=False)
        # Set default photoset
        if self.photoset is None:
            if not PhotoSet.objects.filter(user=self.user, photoset_type=3).exists():
                PhotoSet.objects.create(user=self.user, photoset_type=3, title='Profile Pictures')
                self.photoset = PhotoSet.objects.get(user=self.user, photoset_type=3)
            if PhotoSet.objects.filter(user=self.user, photoset_type=3).exists():
                self.photoset = PhotoSet.objects.get(user=self.user, photoset_type=3)
        # Model Save override 
        if self.id is None:
            saved_image = self.image
            self.image = None
            super(Avatar, self).save(*args, **kwargs)
            self.image = saved_image
        super(Avatar, self).save(force_insert, force_update, *args, **kwargs)

当我使用 Django Rest Framework 创建序列化程序 POST 时:

class AvatarCreateUpdateSerializer(ModelSerializer):
    class Meta:
        model = Avatar
        fields = [
            'user',
            'image',
            'caption',
            'is_public',
        ]

出现问题:

在线错误日志跟踪: super(Avatar, self).save(force_insert, force_update, *args, **kwargs)

为什么我会遇到这个问题,我该如何解决这个问题?提前谢谢!

【问题讨论】:

【参考方案1】:

您在模型的基类上调用了两次save() 方法:

这里:

 super(Avatar, self).save(*args, **kwargs)

这里:

 super(Avatar, self).save(force_insert, force_update, *args, **kwargs)

正如下面的评论所说,您应该使用update_or_createget_or_create 来处理这种情况。

【讨论】:

而且你基本上也可以使用更新而不是像那样保存它:***.com/questions/6382806/… 当我删除这一行时:super(Avatar, self).save(*args, **kwargs)。我无法在路径中使用 avatar_id 预先保存。文件路径来:users/1/avatar/1_None.jpg 代替 users/1/avatar/1_9.jpg (9 是 avatar_id) @Clement 你能帮我把这条线改成get_or_create吗?兄弟 我建议您先自己尝试一下。编程最好是边做边学。尝试后,如果您仍然卡住,请发布一个新问题,我很乐意为您提供帮助。祝你好运! 感谢@ClémentDenoix。我会试试的【参考方案2】:

已修复问题:将 super(Avatar, self).save(force_insert, force_update, *args, **kwargs) 更改为 super(Avatar, self).save(*args, **kwargs)

【讨论】:

【参考方案3】:

问题是保存函数被其余框架传递“forced_insert=True”。当您使用相同的数据保存两次时,它会尝试强制插入相同的主键两次。

一个解决方案是在第一次保存后将强制插入重置为 添加

kwargs['force_insert'] = False

在第二次保存之前。这将允许 Django 使用更新方法,因此不会尝试两次创建相同的主键。

【讨论】:

以上是关于Django Rest Framework:重复键值违反唯一约束的主要内容,如果未能解决你的问题,请参考以下文章

如何处理 django-rest-framework 中 url 模式中的外键关系

django rest framework 外键序列化方法与问题总结

如何避免 Django Forms 和 Django Rest Framework Serializers 中的代码重复?

在序列化程序中编辑外键字段 - Django Rest Framework

将 APIView 添加到 Django REST Framework 可浏览 API [重复]

修复 Django Rest Framework 模型序列化程序相关主键查询集中的错误