Django REST framework: save related models in ModelViewSet Django REST framework: save related models in ModelViewSet django django

Django REST framework: save related models in ModelViewSet


I was dealing with similiar issue this week and I found out, that django rest framework 3 actually supports nested writable serialisation (http://www.django-rest-framework.org/topics/3.0-announcement/#serializers in subchapter Writable nested serialization.)

Im not sure if nested serialisers are writable be default, so I declared them:

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

and you should rewrite your create methon inside 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

if this structure Step.objects.create(recipe=recipe, **step) wont work, maybe you have to select data representeng each field separatly from steps_data / ingredients_data.

This is link to my earlier (realted) question/answer on stack: How to create multiple objects (related) with one request in DRF?


I think that I get the answer.

class RecetaSerializer(serializers.ModelSerializer):

ingredientes = IngredientesSerializer(many=True, partial=True)autor = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())depth = 2class 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 datadef 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

It's important to override to_internal_value(). I had problems with the function is_valid(). So every change make in the function to_internal_value() is before the function is_valid()