本文介绍了<<模型>与此< field>已经存在”在PUT调用上-Django REST Framework的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在执行HTTP PUT调用以更新具有嵌套关系的对象的数据,但遇到以下错误:

I'm doing a HTTP PUT call to update the data of an object with a nested relationship, and I'm met by the following error:

带有该条的AttributeChoice已存在。

"AttributeChoice with this slug already exists."

这之所以令人困惑,是因为我正在执行 HTTP PUT 调用,并且我希望它会将其视为 UPDATE 而不是 CREATE 。

The reason why this is confusing is because I'm doing a HTTP PUT call and I expect it to treat it as an UPDATE and not a CREATE.

我的模型如下:

class Attribute(models.Model):
    name        = models.CharField(max_length=100)
    text_input  = models.BooleanField(default=False)
    slug        = models.SlugField(unique=True)

class AttributeChoice(models.Model):
    attribute   = models.ForeignKey(Attribute)
    value       = models.CharField(max_length=100)
    slug        = models.SlugField(unique=True)

我的序列化器如下:

class AttributeChoiceSerializer(serializers.ModelSerializer):
    class Meta:
        model = AttributeChoice
        fields = '__all__'
        extra_kwargs = {'id': {'read_only': False}}

class AttributeSerializer(serializers.ModelSerializer):
    attributechoice_set = AttributeChoiceSerializer(many=True)
    class Meta:
        model = Attribute
        fields = ('id', 'name', 'text_input', 'slug', 'attributechoice_set')

    def update(self, instance, validated_data):
        choice_data = validated_data.pop('attributechoice_set') 
        for choice in choice_data:
        
            # If id is within the call, then update the object with matching id
            if 'id' in choice:
                try:
                    choice_obj = AttributeChoice.objects.get(pk=choice['id'])
                    choice_obj.value = choice['value']
                    choice_obj.slug = choice['slug']
                    choice_obj.attribute = instance
                # If ID is not found, then create a new object
                except AttributeChoice.DoesNotExist:
                    choice_obj = AttributeChoice(**choice)
            # If no ID within the call, create a new object.
            else:
                choice_obj = AttributeChoice(**choice)

            choice_obj.save()

        return instance

调试:
即使我删除了 update()功能,我仍然收到相同的错误。我相信在ViewSet中调用 .is_valid()时会报告该错误。因此,不是导致 update()的原因。

Debug:Even if I remove the update() function, I still get the same error. I believe the error is reported from when .is_valid() is called in the ViewSet. So it's not the update() that causes it.

此外,如果我删除了 attributechoice_set = AttributeChoiceSerializer( many = True),只需在 fields =()字段中包含 attributechoice_set 错误消失了,但是我需要那一行才能使其余代码正常工作。

Also, if I remove attributechoice_set = AttributeChoiceSerializer(many=True) and just include the attributechoice_set in the fields = (), the error disappears, but I need that line for the rest of the code to work.

推荐答案

即使在进行更新时, ,这并不意味着嵌套数据将被更新。

Even through you're doing an update, it doesn't mean the nested data will just be updated.

您只是在说要更新最上面的对象。

You're simply saying that you want to update the top most object.

在某些情况下,您将在更新最顶层的嵌套对象的同时删除或创建新的嵌套对象。

In some cases, you'll be removing or creating new nested objects while updating the top most one.

因此,DRF默认考虑嵌套对象是用于创建的。您可以通过显式删除嵌套序列化程序上的唯一约束来解决此问题:

Therefore DRF considers by default that nested objects are for creation. You can work around this by explicitly removing the unique constraint on the nested serializer:

class AttributeChoiceSerializer(serializers.ModelSerializer):
    class Meta:
        model = AttributeChoice
        fields = '__all__'
        extra_kwargs = {
            'id': {'read_only': False},
            'slug': {'validators': []},
        }

这篇关于<<模型>与此< field>已经存在”在PUT调用上-Django REST Framework的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-31 22:48