Django REST框架:在ModelViewSet中保存相关模型

时间:2015-02-11 15:55:16

标签: django django-forms django-rest-framework formset

我试图弄清楚如何使用Django REST框架保存相关模型。 在我的应用中,我有一个模型Recipe,其中包含2个相关模型:RecipeIngredientRecipeStepRecipe对象必须至少包含3个相关RecipeIngredient和3 RecipeStep。在引入REST框架之前,我使用了带有两个formset的Django CreateView,并且保存过程如下(遵循form_valid()中的代码):

def save_formsets(self, recipe):
    for f in self.get_formsets():
        f.instance = recipe
        f.save()

def save(self, form):
    with transaction.atomic():
        recipe = form.save()
        self.save_formsets(recipe)
    return recipe

def formsets_are_valid(self):
        return all(f.is_valid() for f in self.get_formsets())

def form_valid(self, form):
    try:
        if self.formsets_are_valid():
            try:
                return self.create_ajax_success_response(form)
            except IntegrityError as ie:
                return self.create_ajax_error_response(form, {'IntegrityError': ie.message})
    except ValidationError as ve:
        return self.create_ajax_error_response(form, {'ValidationError': ve.message})
    return self.create_ajax_error_response(form)

现在我有RecipeViewSet

class RecipeViewSet(ModelViewSet):
    serializer_class = RecipeSerializer
    queryset = Recipe.objects.all()
    permission_classes = (RecipeModelPermission, )

使用RecipeSerializer

class RecipeSerializer(serializers.ModelSerializer):
    class Meta:
        model = Recipe
        fields = (
            'name', 'dish_type', 'cooking_time', 'steps', 'ingredients'
        )

    ingredients = RecipeIngredientSerializer(many=True)
    steps = RecipeStepSerializer(many=True)

这些是相关的序列化器:

class RecipeIngredientSerializer(serializers.ModelSerializer):
    class Meta:
        model = RecipeIngredient
        fields = ('name', 'quantity', 'unit_of_measure')

class RecipeStepSerializer(serializers.ModelSerializer):
    class Meta:
        model = RecipeStep
        fields = ('description', 'photo')

现在......我应该如何验证相关模型(RecipeIngredientRecipeStep)并在RecipeViewSet create()时保存它们方法被称为? ({1}}中的is_valid()实际上忽略了嵌套关系,仅报告与主模型RecipeSerializer相关的错误。 目前我试图覆盖Recipe中的is_valid()方法,但不是那么简单......任何想法?

2 个答案:

答案 0 :(得分:17)

我本周正在处理类似的问题而且我发现,django rest framework 3实际上支持嵌套可写序列化(http://www.django-rest-framework.org/topics/3.0-announcement/#serializers在子章节可写嵌套序列化中。)

我不确定嵌套的序列化程序是否可写是默认的,所以我声明了它们:

ingredients = RecipeIngredientSerializer(many=True, read_only=False)
steps = RecipeStepSerializer(many=True, read_only=False)

你应该在RecipeSerializer中重写你的创建方法:

class RecipeSerializer(serializers.ModelSerializer):
    ingredients = RecipeIngredientSerializer(many=True, read_only=False)
    steps = RecipeStepSerializer(many=True, read_only=False)

    class Meta:
        model = Recipe
        fields = (
            'name', 'dish_type', 'cooking_time', 'steps', 'ingredients'
        )

    def create(self, validated_data):
        ingredients_data = validated_data.pop('ingredients')
        steps_data = validated_data.pop('steps')
        recipe = Recipe.objects.create(**validated_data)
        for ingredient in ingredients_data:
            #any ingredient logic here
            Ingredient.objects.create(recipe=recipe, **ingredient)
        for step in steps_data:
            #any step logic here
            Step.objects.create(recipe=recipe, **step)
        return recipe

如果这个结构Step.objects.create(recipe = recipe,** step)不起作用,也许你必须从steps_data / ingredients_data中分别选择代表每个字段的数据。

这是我在堆栈上的早期(实际)问题/答案的链接:How to create multiple objects (related) with one request in DRF?

答案 1 :(得分:1)

我认为我得到了答案。

class RecetaSerializer(serializers.ModelSerializer):

position: absolute;

重写to_internal_value()很重要。我遇到了函数is_valid()的问题。因此,函数to_internal_value()中的每个更改都在函数is_valid()

之前