首页 > 解决方案 > 覆盖 Django 序列化程序中的“创建”函数

问题描述

我想知道如何处理 POST 请求以正确保存传入数据,具有这样的模型:

class Recipe(models.Model):
    author = models.ForeignKey('auth.user', related_name='recipes', on_delete=models.CASCADE)
    image = models.TextField(default='None')
    name = models.CharField(max_length=100)
    description = models.TextField(default='No description')
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.name

class Ingredient(models.Model):
    image = models.TextField(default='None')
    name = models.CharField(max_length=100)

    description = models.TextField(default='No description')
    price = models.DecimalField(max_digits=8, decimal_places=3)
    unit_price = models.DecimalField(max_digits=8, decimal_places=3)
    unit_quantity = models.CharField(max_length=20)

    def __str__(self):
        return self.name

我想避免重复成分对象,因此为了在配方中提供特定成分的数量,我创建了一个将成分与配方绑定的 RecipesIngredient 模型,但也包含一定数量的这种成分:

class RecipesIngredient(models.Model):
        recipe = models.ForeignKey(Recipe, related_name='ingredients', on_delete=models.CASCADE)
        ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
        quantity = models.CharField(max_length=100)

        def __str__(self):
            return self.quantity

我还为这些模型准备了一些序列化程序:

class IngredientSerializer(HyperlinkedModelSerializer):
    class Meta:
        model = Ingredient
        fields = (
            'url',
            'image',
            'name',
            'description',
            'price',
            'unit_price',
            'unit_quantity'
        )

class RecipesIngredientSerializer(HyperlinkedModelSerializer):
    ingredient_name = ReadOnlyField(source='ingredient.name')
    ingredient_price = ReadOnlyField(source='ingredient.price')
    ingredient_unit_price = ReadOnlyField(source='ingredient.unit_price')
    ingredient_unit_quantity = ReadOnlyField(source='ingredient.unit_quantity')

    class Meta:
        model = RecipesIngredient
        fields = (
            'url',
            'ingredient_name',
            'quantity',
            'ingredient_price',
            'ingredient_unit_price',
            'ingredient_unit_quantity'
        )

class RecipeListSerializer(HyperlinkedModelSerializer):
    author = ReadOnlyField(source='author.username')
    author_url = ReadOnlyField(source='author.url')

    class Meta:
        model = Recipe
        fields = (
            'url',
            'author',
            'author_url',
            'image',
            'name',
            'description',
            'votes'
        )


class RecipeDetailSerializer(HyperlinkedModelSerializer):
    author = ReadOnlyField(source='author.username')
    author_url = ReadOnlyField(source='author.url')
    ingredients = RecipesIngredientSerializer(many=True)

    class Meta:
        model = Recipe
        fields = (
            'url',
            'author',
            'author_url',
            'image',
            'name',
            'description',
            'ingredients',
            'votes'
        )

但在这种情况下,我必须首先创建一个 Recipe 实例并将其保存到 DB,然后对成分执行相同操作,以便能够在 RecipesIngredient 中“绑定”它们。是否可以仅通过一个 POST 请求在下面查看来处理这种情况?

#
# path('recipes/', views.RecipeList.as_view(), name='recipe-list')
#
class RecipeList(generics.ListCreateAPIView):
    queryset = Recipe.objects.all()
    serializer_class = RecipeListSerializer

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

@EDIT我忘记了这个线程,但问题现在解决了。我准备了另一个仅用于 CREATE 目的的序列化程序,并覆盖了此序列化程序的“创建”功能。:

class RecipeCreateSerializer(HyperlinkedModelSerializer):
    #author = ReadOnlyField(source='author.username')
    #author_url = ReadOnlyField(source='author.url')
    recipes_ingredients = RecipesIngredientCreateSerializer(many=True)

    def create(self, validated_data):
        recipes_ingredients = validated_data.pop('recipes_ingredients')
        recipe_instance = super().create(validated_data)

        for recipe_ingredient in recipes_ingredients:

            ingredient_data = recipe_ingredient.pop('ingredient')
            ingredient_instance = Ingredient(
                image=ingredient_data['image'],
                name=ingredient_data['name'],
                description=ingredient_data['description'],
                price=ingredient_data['price'],
                unit_price=ingredient_data['unit_price'],
                unit_quantity=ingredient_data['unit_quantity'],
            )
            ingredient_instance.save()


            recipes_ingredient_instance = RecipesIngredient(
                recipe=recipe_instance,
                ingredient=ingredient_instance,
                quantity=recipe_ingredient['quantity']
            )
            recipes_ingredient_instance.save()
        return recipe_instance

    class Meta:
        model = Recipe
        fields = (
            'url',
            'image',
            'name',
            'description',
            'votes',
            'recipes_ingredients',
        )

JSON 文件现在看起来也有点不同,但一切正常:

{
    "image": "image-url",
    "name": "recipes-name",
    "description": "recipes-description",
    "votes": 0,
    "recipes_ingredients": [
        {
            "quantity": "ingredients-quantity",
            "ingredient": {
                "image": "image-url",
                "name": ingredient-name",
                "description": "ingredient-description",
                "price": 3.6,
                "unit_price": 0.36,
                "unit_quantity": "100ML"
            }
        },
        {
            "quantity": "ingredients-quantity",
            "ingredient": {
                "image": "image-url",
                "name": ingredient-name",
                "description": "ingredient-description",
                "price": 0.3,
                "unit_price": 0.3,
                "unit_quantity": "EACH"
            }
        },
        {
            "quantity": "ingredients-quantity",
            "ingredient": {
                "image": "image-url",
                "name": ingredient-name",
                "description": "ingredient-description",
                "price": 2.0,
                "unit_price": 0.8,
                "unit_quantity": "KG"
            }
        }
    ]
}

标签: djangodjango-rest-frameworkdjango-serializer

解决方案


推荐阅读