Django通过视图创建带S3图片对象时主键重复唯一约束错误如何解决
问题原因
主键冲突是因为模型被多次重复保存触发的,核心原因有两个:
ImageField实例调用save()方法时默认会触发所属模型的save()操作。你在image_resize函数末尾调用image.save()时没有关闭这个默认行为,导致模型save方法递归触发,出现重复提交。- 序列化器
create方法中,Shop.objects.create()本身已经完成了对象的入库保存,后续额外调用的shop.save()属于多余操作,进一步加重了重复保存的问题。
这也能解释为什么不带图片的时候运行正常:没有图片就不会触发image_resize逻辑,也就不会产生额外的save调用。Django管理后台的文件处理逻辑本身规避了这种重复触发的问题,所以也不会报错。
解决方案
按顺序修改代码即可:
1. 修改图片保存逻辑,避免触发模型二次保存
打开utils.py,找到image_resize函数的最后一行,添加save=False参数:
# 原代码 # image.save(img_filename, file_object) # 修改为 image.save(img_filename, file_object, save=False)
后续模型本身的super().save()会完成数据入库,不需要ImageField单独触发保存。
2. 删除序列化器中多余的保存操作
打开serializers.py,找到create方法,删除shop = Shop.objects.create(**validated_data, path=path)之后的shop.save()语句:
def create(self, validated_data): # 原有path生成逻辑保持不变 shop = Shop.objects.create(**validated_data, path=path) # 删除下面这行多余的save # shop.save() return shop
3. 优化模型save方法的异常捕获(可选,建议修改)
当前模型save方法使用了裸except,会吞掉所有异常,不利于后续问题排查,建议修改为仅捕获查询不到对象的异常:
def save(self, *args, **kwargs): try: this = Shop.objects.get(id=self.id) # 原有更新逻辑保持不变 except Shop.DoesNotExist: # 原有创建逻辑保持不变 super().save(*args, **kwargs)
修改完成后重启服务即可解决主键冲突问题。
内容的提问来源于stack exchange,提问作者Bastien
相关产品推荐
相关产品推荐

