首页 > 解决方案 > DRF:深度 > 1 的嵌套序列化程序

问题描述

我正在研究“嵌套嵌套”序列化程序,其中有一个嵌套序列化程序嵌套在另一个序列化程序中。这是一种烹饪服务,其中食谱有多个方向,每个方向都有多种成分。我用外键设置了它。

这是我的模型:

class Category(models.Model):
    """Model representing a recipe category"""
    name = models.CharField(max_length=200, help_text="Enter a recipe category (e.g Baking)")

    def __str__(self):
        """String for representing the Model object."""
        return self.name

class Ingredient(models.Model):
    """Model representing an ingredient in a direction"""
    name = models.CharField(max_length=250, help_text="The ingredient's name")
    quantity = models.CharField(max_length=200, help_text="How much of this ingredient.")
    direction = models.ForeignKey("Direction", help_text="This ingredient's direction", on_delete=models.CASCADE, related_name='ingredients')

    def __str__(self):
        """String for representing this recipe ingredient"""
        return f'{self.quantity} {self.ingredient}'

class Direction(models.Model):
    """Model representing a step in a recipe"""
    title=models.CharField(max_length=200)
    text=models.TextField(blank=True, help_text="Describe this step.")

    recipe=models.ForeignKey("Recipe", help_text="This direction's recipe", on_delete=models.CASCADE, related_name='directions')


    def __str__(self):
        """String for representing the Direction"""
        return self.title

class Recipe(models.Model):
    """Model representing a recipe."""
    title = models.CharField(max_length=200)

    notes = models.TextField(max_length=1000, help_text="Enter notes, reviews, ...")

    photos = models.ImageField(null=True, blank=True)

    category = models.ForeignKey(Category, help_text="This recipe's category", on_delete=models.CASCADE, related_name='recipes')

    def __str__(self):
        """String for representing the Model object."""
        return self.title

    def get_absolute_url(self):
        """Returns the url to access a detail record for this recipe."""

我阅读了文档并认为我可以在另一个中使用嵌套序列化程序,这给我一个错误,指出“禁止直接分配到相关集的反面”。

然后我通过使用这些序列化程序使它工作:

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ('name',)

    def create(self, validated_data):
        category = Category.objects.create(**validated_data)
        return category


class IngredientSerializer(serializers.ModelSerializer):
    class Meta:
        model = Ingredient
        fields = ('quantity', 'name',)

    def create(self, validated_data):
        ingredient = Ingredient.objects.create(**validated_data)
        return ingredient

    def update(self, instance, validated_data):
        instance.quantity = validated_data.get('quantity', instance.quantity)
        instance.name = validated_data.get('name', instance.name)
        instance.direction = validated_data.get('direction', instance.direction)
        instance.save()
        return instance

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

    class Meta:
        model = Direction
        fields = ('title', 'text', 'ingredients', )

    def create(self, validated_data):
        direction = Direction.objects.create(**validated_data)

        return direction

    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        instance.text = validated_data.get('text', instance.text)
        instance.recipe = validated_data.get('recipe', instance.recipe)

        instance.save()
        return instance


class RecipeSerializer(serializers.ModelSerializer):
    directions = DirectionSerializer(many=True)
    category = CategorySerializer()

    class Meta:
        model = Recipe
        fields = ('title', 'notes', 'photos', 'category', 'directions')

    def create(self, validated_data):
        directions_data = validated_data.pop('directions')
        category_data = validated_data.pop('category')
        category = Category.objects.create(**category_data)
        validated_data["category"] = category
        recipe = Recipe.objects.create(**validated_data)
        recipe.category = category
        for direction_data in directions_data:
            ingredients_data = direction_data.pop("ingredients")
            direction = Direction.objects.create(recipe=recipe, **direction_data)
            for ingredient_data in ingredients_data:
                Ingredient.objects.create(direction=direction, **ingredient_data)
        return recipe

    def update(self, instance, validated_data):
        instance.title = validated_data.get('title', instance.title)
        instance.notes = validated_data.get('notes', instance.notes)
        instance.photos = validated_data.get('photos', instance.photos)
        instance.category = validated_data.get('category', instance.category)

        instance.save()
        return instance

我不确定,此时实际上需要什么。基本上我在配方的 create() 函数中创建嵌套结构。

现在是真正的问题:这确实感觉像一个黑客。这是实现多个嵌套序列化程序的正确且预期的方式吗?

如果我这样做,我什至需要 create() 和 update() 函数吗?

非常感谢。

标签: pythondjangodjango-rest-framework

解决方案


推荐阅读