Django Rest Framework可写嵌套序列化器

bob*_*byz 37 python django serialization django-rest-framework

我正在编写一个食谱组织者作为课程的示例项目.除了使用一些非常基本的功能之外,我对DRF不是很有经验.这是目标:

使用相关成分创建新配方.在创建Recipe对象的同时创建Ingredient对象.

models.py:

class Ingredient(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class Recipe(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True, null=True, help_text="This is a quick description of your recipe")
    directions = models.TextField(help_text="How to make the recipe")
    ingredients = models.ManyToManyField(Ingredient)

    def __str__(self):
        return self.name
Run Code Online (Sandbox Code Playgroud)


serializers.py

class IngredientSerializer(serializers.ModelSerializer):

    class Meta:
        model = Ingredient


class RecipeSerializer(serializers.ModelSerializer):
    ingredients = IngredientSerializer(many=True)

    class Meta:
        model = Recipe

    def create(self, validated_data):
        ingredients_data = validated_data.pop('ingredients')
        recipe = Recipe.objects.create(**validated_data)
        for ingredient_data in ingredients_data:
            Ingredient.objects.create(**ingredient_data)
        return recipe
Run Code Online (Sandbox Code Playgroud)

这样可以在数据库中成功创建Recipe对象和Ingredients对象,但不会将Ingredients列表与Recipe关联.我认为这是因为当我运行时ingredients_data = validated_data.pop('ingredients'),validated_data字典会删除其成分,所以当我创建一个新的食谱使用时validated_data,没有相关的成分.

然而,我似乎无法找到一种方法来保持配方相关的成分.

bob*_*byz 41

我发现在创建所有未创建的对象之前,无法建立ManyToMany关系.(请参阅关于多对多关系的Django Docs 页面.)

这是工作代码:

serializers.py

class RecipeSerializer(serializers.ModelSerializer):
    ingredients = IngredientSerializer(many=True)

    class Meta:
        model = Recipe

    def create(self, validated_data):
        ingredients_data = validated_data.pop('ingredients')
        recipe = Recipe.objects.create(**validated_data)

        for ingredient in ingredients_data:
            ingredient, created = Ingredient.objects.get_or_create(name=ingredient['name'])
            recipe.ingredients.add(ingredient)
        return recipe
Run Code Online (Sandbox Code Playgroud)

更新:

根据@StevePiercy的要求,下面是我的update()代码.但是,多年来我没有看过这个,如果它是正确的还是好的,我也不知道.我已经有一段时间没有在Python或Django上工作过了,所以请耐心等待:

def update(self, instance, validated_data):
    ingredients_data = validated_data.pop('ingredients')

    instance.name = validated_data.get('name', instance.name)
    instance.description = validated_data.get('description', instance.description)
    instance.directions = validated_data.get('directions', instance.directions)
    instance.photo = validated_data.get('photo', instance.photo)

    ingredients_list = []

    for ingredient in ingredients_data:
        ingredient, created = Ingredient.objects.get_or_create(name=ingredient["name"])
        ingredients_list.append(ingredient)

    instance.ingredients = ingredients_list
    instance.save()
    return instance
Run Code Online (Sandbox Code Playgroud)


fer*_*eek 9

这是这个问题的一个小例子.

由此改变那部分代码.

    def create(self, validated_data):
        ingredients_data = validated_data.pop('ingredients')
        recipe = Recipe.objects.create(**validated_data)

        for ingredient in ingredients_data:
            ingredient, created = Ingredient.objects.get_or_create(name=ingredient['name'])
            recipe.ingredients.add(ingredient)
        return recipe
Run Code Online (Sandbox Code Playgroud)

这是编辑的方法,在您想要编辑时会导致错误.

    def update(self, instance, validated_data):
        ingredients_data = validated_data.pop('ingredients')
        instance.name = validated_data['name']
        instance.description = validated_data['description']
        instance.directions = validated_data['directions']

        for ingredient in ingredients_data:
            ingredient, created = Ingredient.objects.get_or_create(name=ingredient['name'])
            recipe.ingredients.add(ingredient)
        return instance
Run Code Online (Sandbox Code Playgroud)

这是一个带有示例的链接,这个代码类似于另一个答案,但如果你想尝试代码,这里没有问题就是repo.祝好运! DRF嵌套序列化程序