django 如何正确更新多对多嵌套序列化程序?

zf9nrax1  于 2022-12-14  发布在  Go
关注(0)|答案(2)|浏览(174)

我已经能够复制create方法来在POST请求中添加正确的嵌套序列化器。但是,我在PUT或PATCH中更新时仍然有问题。当使用PUT或PATCH请求并传递整个对象数据或“brands”数据时,它只会在传递的位置更新。因此,如果我有一个具有3个值的对象:

"brands": [
            {
                "id": 1,
                "name": "Brand 1 Test"
            },
            {
                "id": 2,
                "name": "Brand 2 Test"
            },
            {
                "id": 3,
                "name": "Brand 3 Test"
            }
}

如果我通过:

"brands": [
            {
                "id": 1,
                "name": "Brand 1 Test"
            },
            {
                "id": 2,
                "name": "Brand 2 Test"
            }

它会给予我同样的3个品牌的列表。但如果我这样做在相反的顺序,它会更新,并添加第三品牌。我不知道是什么原因造成的。这里的代码我有:
型号

class Brand(models.Model):
    name = models.CharField(max_length=500)

class Incentive(models.Model):
    name = models.CharField(max_length=500)
    brands = models.ManyToManyField(Brand, related_name='incentives_brand')
    start_dt = models.DateTimeField(auto_now_add=False, blank=True, null=True)
    end_dt = models.DateTimeField(auto_now_add=False, blank=True, null=True)

串行器

class BrandSerializer(serializers.ModelSerializer):
    class Meta:
        model = Brand
        depth = 1
        fields = ['id', 'name']

class IncentiveSerializer(serializers.ModelSerializer):
    brands = BrandSerializer(many=True)
    
    class Meta:
        model = Incentive
        fields = ['id', 'name', 'brands', 'start_dt', 'end_dt']
    
    def create(self, validated_data):
        brands = validated_data.pop('brands', [])
        instance = Incentive.objects.create(**validated_data)
        for brand_data in brands:
            brand = Brand.objects.get(**brand_data)
            instance.brands.add(brand)
        return instance 

    def update(self, instance, validated_data):
        brands = validated_data.pop('brands', [])
        instance = super().update(instance, validated_data)
        for brand_data in brands:
            brand = Brand.objects.get(**brand_data)
            instance.brands.add(brand)
        return instance

我认为问题出在这里。如果需要更多的代码,请让我知道(例如,视图,网址)。我猜在更新中我没有正确清空品牌列表。我只是看不到它。任何帮助都将不胜感激。

uqcuzwp8

uqcuzwp81#

我认为这里的线索是你做instance.brands.add,它正是这样做的,添加。而不是像你注意到的那样删除:)
你也有一个set
因此:

brand_objs = []
for brand_data in brands:
    brand = Brand.objects.get(**brand_data)
    brand_objs.append(brand)

instance.brands.set(brand_objs)

但是用法可能会有所不同,我可以想象你也希望能够只添加一个或多个品牌?但是可以使用不同的端点吗?
端点示例

api/incentive/1/brands # get
api/incentive/1/brands # post, set brands?
api/incentive/1/brands/add # add one or more?
api/incentive/1/brands/remove # remove specific one or more?
u3r8eeie

u3r8eeie2#

像这样加上instance.brands.clear()
这将清除相关品牌,以便您可以更新它们。

def update(self, instance, validated_data):
    brands = validated_data.pop('brands', None)
    instance = super().update(instance, validated_data)
    # The condition below will update brands only if brands were 
    # specified in the request body
    if brands is not None:
        instance.brands.clear() # Clear related brands
        for brand_data in brands:
            brand = Brand.objects.get(**brand_data)
            instance.brands.add(brand)
        return instance

相关问题