如何更新m2m关系

时间:2018-06-06 14:17:32

标签: python django django-rest-framework

我试图通过在SerializerClass上实现update()方法来更新提交的数据。但是,我不知道如何访问当前实例的当前成分,也不知道如何遍历验证数据,以便我可以正确分配键和值。任何建议将不胜感激!

我的序列化工具

class RecipeSerializer(ModelSerializer):
    ingredients = IngredientSerializer(many=True)
    owner = ReadOnlyField(source='owner.username')

    class Meta:
        fields = ['owner', 'name', 'description', 'image', 'ingredients']
        model = Recipe

    def create(self, validated_data):
        ingredient_datas = validated_data.pop('ingredients')
        recipe = Recipe.objects.create(**validated_data)
        for ingredient_data in ingredient_datas:
            recipe.ingredients.create(**ingredient_data)
        return recipe

    def update(self, instance, validated_data):
        instance.name = validated_data.get('name', instance.name)
        instance.description = validated_data.get('description', instance.description)
        instance.image = validated_data.get('image', instance.image)

        for ingredient in validated_data.get('ingredients'):
            for key, value in ingredient.items():
                print(key, value)
                instance.ingredient.name = value
                instance.ingredient.amount = value
        instance.save()
        return instance

我的模特

class Recipe(models.Model):
    owner = models.ForeignKey('auth.User', related_name='recipes', on_delete=models.CASCADE)
    name = models.CharField(max_length=100)
    description = models.TextField(max_length=200, blank=True)
    image = models.CharField(max_length=100, blank=True)
    ingredients = models.ManyToManyField(Ingredient, related_name='recipes')

class Ingredient(models.Model):
    name = models.CharField(max_length=50)
    amount = models.IntegerField(default=1)

一些窗口外壳输出

打印(validated_data)

{'name': 'bedddef', 'description': 'gdddoot', 'image': 'httpdddlo', 'ingredients': [OrderedDict([('name', 'tomatoes'), ('amount', 2)]), OrderedDict([('name', 'bread'), ('amount', 3)])]}

for key,value.items()中的值:
    打印(键,值)

name tomatoes
amount 2
name bread
amount 3

最近(今天) 我重新创建了整个api,因为我失去了它。我尝试使用相同的代码熊建议使用Ingredient.objects.get_or_create()的update()方法,但我得到一个错误说。

MultipleObjectsReturned at / api / recipes / 3 / get()返回多个成分 - 它返回2!

由于错误我替换get_or_create()只是create()会是一个糟糕的解决方案吗?

   def update(self, instance, validated_data):
        instance.name = validated_data.get('name', instance.name)
        instance.descriptions = validated_data.get('descriptions', instance.descriptions)
        instance.image = validated_data.get('image', instance.image)
        ingredients = []
        for ingredient in validated_data.get('ingredients'):
            obj = Ingredient.objects.create(**ingredient)
            ingredients.append(obj)
        print(ingredients)
        instance.ingredients.set(ingredients)
        instance.save()
        return instance

1 个答案:

答案 0 :(得分:1)

您可以使用m2m RelatedManager的set方法

def update(self, instance, validated_data):
    instance.name = validated_data.get('name', instance.name)
    instance.description = validated_data.get('description', instance.description)
    instance.image = validated_data.get('image', instance.image)
    ingredients = []
    for ingredient in validated_data.get('ingredients'):
        obj, _ = Ingredient.objects.get_or_create(**ingredient)
        ingredients.append(obj)
    instance.ingredients.set(ingredients)
    #                 ^^^^^^
    instance.save()
    return instance

详细信息:模型实例的get_or_create返回元组和bool值是创建新实例的,但我们不需要bool,所以为了使代码更具可读性,只需赋值变量{{ 1}}

_