Django : 错误:'重复键值违反唯一约束'。

1 人关注

在为我的网站创建一个新的对象时,我必须用s3保存图片。

我有一个代码来保存我的图片,我在模型的保存方法中使用。

当我使用 django 管理面板时,我可以很容易地创建我的对象,没有任何错误。

当我在不添加图片的情况下发送我的数据时,它也工作得很好。

但是当我试图通过我的视图来创建我的对象时,我得到了这个错误。 Error: 'duplicate key value violates unique constraint « store_shop_pkey »' DETAIL: key (id)=(37) already exists

我认为在我的序列化器的创建方法中,我试图保存我的对象两次:一次是图像,一次是我对象的其他键。

我不知道如何解决这个问题。

它在PUT方法中运行良好。

下面是我的代码。

models.py :

class Shop(models.Model):
    name = models.CharField(max_length=255)
    category = models.ForeignKey(ShopCategory, on_delete=models.SET_NULL, null=True, blank=True)
    description = models.TextField(blank=True, null=True)
    path = models.CharField(max_length=255, unique=True, null=True, blank=True) # Set a null and blank = True for serializer
    mustBeLogged = models.BooleanField(default=False)
    deliveries = models.FloatField(validators=[MinValueValidator(0),], default=7)
    message = models.TextField(null=True, blank=True)
    banner = models.ImageField(null=True, blank=True)
    def save(self, *args, **kwargs):
        try:
            """If we want to update"""
            this = Shop.objects.get(id=self.id)
            if self.banner:
                image_resize(self.banner, 300, 300)
                if this.banner != self.banner:
                    this.banner.delete(save=False)
            else:
                this.banner.delete(save=False)
        except:
            """If we want to create a shop"""
            if self.banner:
                image_resize(self.banner, 300, 300)
        super().save(*args, **kwargs)
    def delete(self):
        self.banner.delete(save=False)
        super().delete()
    def __str__(self):
        return self.name

utils.py 。

def image_resize(image, width, height):
    # Open the image using Pillow
    img = Image.open(image)
    # check if either the width or height is greater than the max
    if img.width > width or img.height > height:
        output_size = (width, height)
        # Create a new resized “thumbnail” version of the image with Pillow
        img.thumbnail(output_size)
        # Find the file name of the image
        img_filename = Path(image.file.name).name
        # Spilt the filename on “.” to get the file extension only
        img_suffix = Path(image.file.name).name.split(".")[-1]
        # Use the file extension to determine the file type from the image_types dictionary
        img_format = image_types[img_suffix]
        # Save the resized image into the buffer, noting the correct file type
        buffer = BytesIO()
        img.save(buffer, format=img_format)
        # Wrap the buffer in File object
        file_object = File(buffer)
        # Save the new resized file as usual, which will save to S3 using django-storages
        image.save(img_filename, file_object)

views.py 。

class ShopList(ShopListView):
    """Create shop"""
    def post(self, request):
        """For admin to create shop"""
        serializer = MakeShopSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors)

serializers.py 。

class MakeShopSerializer(serializers.ModelSerializer):
    class Meta:
        model = Shop
        fields = '__all__'
    def create(self, validated_data):
        # validated_data.pop('path')
        path = validated_data["name"].replace(" ", "-").lower()
        path = unidecode.unidecode(path)
        unique = False
        while unique == False:
            if len(Shop.objects.filter(path=path)) == 0:
                unique = True
            else:
                # Generate a random string
                char = "abcdefghijklmnopqrstuvwxyz"
                path += "-{}".format("".join(random.sample(char, 5)))
        shop = Shop.objects.create(**validated_data, path=path)
        shop.save()
        return shop
    def update(self, instance, validated_data):
        #You will have path in validated_data
        #And you may have to check if the values are null
        return super(MakeShopSerializer, self).update(instance, validated_data)

最后,这是我发送的数据。

提前感谢您的帮助

python
django
amazon-s3
django-models
django-rest-framework
Bastien
Bastien
发布于 2021-08-23
2 个回答
Gabriel
Gabriel
发布于 2021-08-23
0 人赞同

下一行有可能是主键的问题。

shop = Shop.objects.create(**validated_data, path=path)

你可以试着把每个属性一个一个的放进去,像这样。

shop = Shop.objects.create(
name=validated_data['name'],
category=validated_data['category'],
path=path)

如果它没有解决你的问题,请从终端发布更多关于你的错误信息

我仍然得到同样的错误...完整的错误是 django.db.utils.IntegrityError: Error: 'duplicate key value violates unique constraint « store_shop_pkey »' DETAIL: key (id)=(37) already exists
@Bastien 请发送带行的完整堆栈错误,你可以在Pastebin上上传堆栈轨迹
Jyothi S
Jyothi S
发布于 2021-08-23
0 人赞同

你的模型的唯一键是 path ,所以在你的序列化器的创建函数里面。

shop = Shop.objects.create(**validated_data, path=path) ,尝试创建一个新的模型。 考虑到你试图添加的第二个实例与之前的实例有相同的路径,在这种情况下,你会得到这个错误,因为 path 应该是唯一的,而你试图用相同的值添加另一个模型,DBMS会拒绝。 你可以尝试的事情之一是。 创建或更新该实例。如果你对更新实例没有意见,当你的第二个实例与前一个实例有相同的路径时,那么使用

Shop.objects.update_or_create(path=path,