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

1szpjjfi  于 2023-08-08  发布在  Go
关注(0)|答案(2)|浏览(122)

我试图弄清楚如何使用Django REST框架保存相关模型。在我的应用程序中,我有一个模型Recipe,其中包含2个相关模型:RecipeIngredientRecipeStep。一个Recipe对象必须至少有3个相关的RecipeIngredient和3个RecipeStep。在引入REST框架之前,我使用了一个带有两个表单集的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')


现在......当调用RecipeViewSetcreate()方法时,我应该如何验证相关模型(RecipeIngredientRecipeStep)并保存它们?(RecipeSerializer中的is_valid()实际上忽略了嵌套关系,只报告与主模型Recipe相关的错误)。目前我试图覆盖RecipeSerializer中的is_valid()方法,但不是那么简单...知道吗?

h79rfbju

h79rfbju1#

这周我处理了类似的问题,我发现django rest framework 3实际上支持嵌套可写序列化(http:www.django-rest-framework.org/topics/3.0-announcement/#serializers在子章节Writable nested serialization中)。
我不确定嵌套序列化器是否是可写的,所以我声明了它们:

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

字符串
你应该在RecipeSerializer中重写你的create methon:

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?

6ojccjat

6ojccjat2#

我想我知道答案了。

class RecetaSerializer(serializers.ModelSerializer):

    ingredientes = IngredientesSerializer(many=True, partial=True)
    autor = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
    depth = 2

    class Meta:
        model = Receta
        fields = ('url','pk','nombre','foto','sabias_que','ingredientes','pasos','fecha_publicacion','autor')   

    def to_internal_value(self,data):

        data["fecha_publicacion"] = timezone.now()
        ingredientes_data = data["ingredientes"]
      
        for ingrediente in ingredientes_data:
                       
            alimento_data = ingrediente["alimento"]
                     
            if Alimento.objects.filter(codigo = alimento_data['codigo']).exists():

                alimento = Alimento.objects.get(codigo= alimento_data['codigo'])              
                ingrediente["alimento"] = alimento

            else:
                alimento = Alimento(codigo = alimento_data['codigo'], nombre = alimento_data['nombre'])
                alimento.save()                
                ingrediente["alimento"] = alimento
        data["ingredientes"] = ingredientes_data
        return data

    def create(self, validated_data):
              
        ingredientes_data = validated_data.pop('ingredientes')
        
        receta_data = validated_data
        usuario = User.objects.get(id = validated_data["autor"])
        receta_data['autor'] = usuario
       
        receta = Receta.objects.create(**validated_data)
        
        
        for ingrediente in ingredientes_data:
            
            alimento_data = ingrediente["alimento"]
            ingrediente = Ingredientes(receta= receta, cantidad = ingrediente['cantidad'], unidad = ingrediente['unidad'], alimento = alimento_data)
            ingrediente.save()
        
        receta.save()
            
            
        return receta

字符串
重写to_internal_value()很重要。函数is_valid()有问题。因此,函数中对_internal_value()的每一个更改都在函数is_valid()之前

相关问题