Отсутствующие данные из 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));
Это все, что я знаю, если у кого-то есть больше информации о том, что нам нужно сделать, пожалуйста, добавьте, так как информации о том, почему так происходит, не так много.