Отсутствующие данные из validated_data в django rest framwork

Я создаю веб-приложение и пытаюсь отправить данные Post в виде FormData в сериализатор Django Rest Framework. В request.data я вижу, что все данные Post есть, однако после проверки и сохранения сериализатора кажется, что некоторые данные не были переданы в validated_data.

Views.py

@api_view(["GET","POST"])
def api_list(request):
    if request.method=="GET":
        data = Recipe.objects.all()

        serializer = RecipeSerializer(data, many=True)

        return Response(serializer.data)

    elif request.method=="POST":
        print("POST recieved")
        print (request.data) <----See below
        serializer = RecipeSerializer(data=request.data)
        print("Validating..")
        if serializer.is_valid():
            print("validated!")
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        print (serializer.errors)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

request.data

<QueryDict: 
{'description': ['"gfdgdfg"'], 
 'name': ['"fdgdfgdf"'], 
 'ingredients': [
     '{"name":"dfgdfg","amount":"gdfgd"}', 
     '{"name":"fdgdfg","amount":"dfgdf"}', 
     '{"name":"dfgdfgdf","amount":"gdfgdf"}'
 ], 
 'directions': [
     '{"content":"gdfgfd"}', 
     '{"content":"gdfgdfg"}', 
     '{"content":"dfgdfdfg"}'
  ], 
'image': [
      <InMemoryUploadedFile: luisana-zerpa-MJPr6nOdppw-unsplash.jpg (image/jpeg)>
 ]
}>

serializer.py

class IngredientSerializer(serializers.ModelSerializer):

    class Meta:
        model = Ingredient
        fields = ('name', 'amount')

class DirectionSerializer(serializers.ModelSerializer):

    class Meta:
        model = Direction
        fields = ('content',)


class RecipeSerializer(serializers.ModelSerializer):
    owner = serializers.StringRelatedField()
    ingredients = IngredientSerializer(many=True, read_only=False)
    directions = DirectionSerializer(many=True, read_only=False)
    class Meta:
        model = Recipe
        fields = (
            'id',
            'name',
            'owner',
            'image',
            'description',
            'created_at',
            'ingredients',
            'directions',
        )


    def create(self, validated_data):
        print (validated_data) <----See Below

        has_ingredients = validated_data.get("ingredients")
        has_directions = validated_data.get("directions")

        if has_ingredients:
            ingredient_data = validated_data.pop('ingredients')
        if has_directions:
            direction_data = validated_data.pop('directions')

        recipe_name = validated_data.get('name')
        recipe_name = recipe_name.replace('"','')

        recipe_description = validated_data.get('description')
        recipe_description = recipe_description.replace('"','')


        recipe = Recipe.objects.create(name=recipe_name, description=recipe_description, image=validated_data.get('image'))
    
        if has_ingredients:
            for ingredient in ingredient_data:
                Ingredient.objects.create(recipe=recipe, name=ingredient.get("name"), amount=ingredient.get("amount"))
        if has_directions:
            for direction in direction_data:
                Direction.objects.create(recipe=recipe, content=direction.get("content"))
        return recipe

validated_data NOTE: Я могу получить это только если я добавляю "required=False" для ингредиента и направления, иначе он просто возвращает 404err

{
 'name': '"fdgdfgdf"', 
 'image': <InMemoryUploadedFile: luisana-zerpa-MJPr6nOdppw-unsplash.jpg (image/jpeg)>, 
 'description': '"gfdgdfg"'
 }

Я пытался найти возможность переопределения метода .is_valid() в сериализаторах, но не смог найти ничего в официальной документации. Если я использую приложение Postman для отправки данных, все работает, однако, когда я отправляю данные с моего фронтенда, это происходит. Интересно, связано ли это с тем, как я отправляю данные, но я не хочу включать слишком много лишнего.

Заранее спасибо за любую помощь :)

Полагаю, что вы забыли отправить ингредиенты и направления в новый рецепт экземпляра.

Поэтому ваша конечная точка POST работает только тогда, когда они не требуются

Вы можете создать связь с Recipe после создания экземпляра Ingredient

ingredient = Ingredient.objects.create(**inputs)
recipe.ingredient = ingredient
recipe.save()

То же самое касается направления:

direction = Direction.objects.create(**inputs)
recipe.direction = direction
recipe.save()

Они уже были проверены в IngredientSerializer и DirectionSerializer, поэтому можно смело создавать отношения с Recipe

Небольшой совет: Если у вас есть флаг has_ingredients, вы, вероятно, имеете в виду, что у вас могут быть рецепты без ингредиентов, в этом случае поле должно быть required=False

Если вам необходимы файлы с ингредиентами и указаниями, вам нужно создать рецепт со всеми исходными данными, например:

recipe = Recipe.objects.create(
    name=recipe_name, 
    description=recipe_description, 
    image=validated_data.get('image'),
    ingredient=ingredient,
    direction=direction
)        

Я понял ответ!

Проблема все время была в том, как я размещал данные.

Оригинально я отправлял данные поста для "ингредиентов" и "направления как здесь"...

ingredients.forEach((ingredient) => {
    formData.append('ingredients',{
        'name':ingredients.name,
        'amount':ingredient.amount
    });
});

У меня также был цикл forEach для "направлений", и он практически следовал тому же шаблону.

Правильный способ отправки списка объектов с использованием multipart/form-data должен выглядеть следующим образом

ingredients.forEach((ingredient, index) => {
        formData.append(`ingredients[${index}]name`, JSON.stringify(ingredient.name));
        formData.append(`ingredients[${index}]amount`, JSON.stringify(ingredient.amount))
    });

Разница в том, что при размещении списка мы должны подробно описать точный путь к каждому элементу списка.

e.g formData.append(ingredients[${index}]name, JSON.stringify(ingredient.name));

Это все, что я знаю, если у кого-то есть больше информации о том, что нам нужно сделать, пожалуйста, добавьте, так как информации о том, почему так происходит, не так много.

Вернуться на верх