I am just learning how to write programs and applications in python. I'm writing a serializer for a Recipe app. But I am getting an error. Please help me understand and write correctly.
Here is the serializer:
class AddRecipeIngredientsSerializer(serializers.ModelSerializer):
id = serializers.PrimaryKeyRelatedField(queryset=Ingredient.objects.all())
amount = serializers.IntegerField()
class Meta:
model = RecipeIngredient
fields = ('id', 'amount')
class AddRecipeSerializer(serializers.ModelSerializer):
image = Base64ImageField()
author = CustomUserSerializer(read_only=True)
ingredients = AddRecipeIngredientsSerializer(many=True)
tags = serializers.PrimaryKeyRelatedField(
queryset=Tag.objects.all(), many=True
)
cooking_time = serializers.IntegerField()
class Meta:
model = Recipe
fields = ('id', 'tags', 'author', 'ingredients',
'name', 'image', 'text', 'cooking_time')
def validate_ingredients(self, data):
ingredients = data[0]
if not ingredients['id']:
raise ValidationError('Не выбрано ни одного ингредиента!')
ingredients_ids = [ingredient['id'] for ingredient in ingredients]
if len(ingredients) != len(set(ingredients_ids)):
raise serializers.ValidationError('Вы не можете добавить один '
'ингредиент дважды')
for ingredient in ingredients['amount']:
print(ingredients)
print(ingredient)
if int(ingredient) <= 0:
raise ValidationError('Количество должно быть положительным!')
pk = int(ingredient['id'])
if pk < 0:
raise ValidationError('id элемента не может быть '
'отрицательным')
return data
def validate_tags(self, data):
if not data:
raise ValidationError('Необходимо отметить хотя бы один тег')
if len(data) != len(set(data)):
raise ValidationError('Один тег указан дважды')
return data
def validate_cooking_time(self, data):
if data <= 0:
raise ValidationError('Время готовки должно быть положительным'
'числом, не менее 1 минуты!')
return data
def add_recipe_ingredients(self, ingredients, recipe):
for ingredient in ingredients:
ingredient_id = ingredient['id']
amount = ingredient['amount']
if RecipeIngredient.objects.filter(
recipe=recipe,
ingredient=ingredient_id,
).exists():
amount = ingredient['amount']
RecipeIngredient.objects.update_or_create(
recipe=recipe,
ingredient=ingredient_id,
defaults={'amount': amount},
)
def create(self, validated_data):
author = self.context.get('request').user
tags_data = validated_data.pop('tags')
ingredients_data = validated_data.pop('ingredients')
recipe = Recipe.objects.create(author=author, **validated_data)
self.add_recipe_ingredients(ingredients_data, recipe)
recipe.tags.set(tags_data)
return recipe
def update(self, recipe, validated_data):
if 'ingredients' in validated_data:
ingredients = validated_data.pop('ingredients')
recipe.ingredients.clear()
self.add_recipe_ingredients(ingredients, recipe)
if 'tags' in validated_data:
tags_data = validated_data.pop('tags')
recipe.tags.set(tags_data)
return super().update(recipe, validated_data)
def to_representation(self, recipe):
return ShowRecipeSerializer(
recipe,
context={'request': self.context.get('request')},
).data
but when i make a POST request to endpoint http://127.0.0.1:8000/api/recipes/
request body is:
{
"author": 1,
"ingredients": [
{
"id": 1,
"name": "колбаса",
"measurement_unit": "гр",
"amount": 100
}
],
"tags": [1],
"image":,
"name": "манная супер каша",
"text": "каша",
"cooking_time": 10
}
That shows an error:
Traceback (most recent call last):
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\rest_framework\viewsets.py", line 114, in view
return self.dispatch(request, *args, **kwargs)
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\rest_framework\views.py", line 505, in dispatch
response = self.handle_exception(exc)
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\rest_framework\views.py", line 465, in handle_exception
self.raise_uncaught_exception(exc)
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\rest_framework\views.py", line 476, in raise_uncaught_exception
raise exc
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\rest_framework\views.py", line 502, in dispatch
response = handler(request, *args, **kwargs)
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\rest_framework\mixins.py", line 18, in create
serializer.is_valid(raise_exception=True)
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\rest_framework\serializers.py", line 234, in is_valid
self._validated_data = self.run_validation(self.initial_data)
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\rest_framework\serializers.py", line 433, in run_validation
value = self.to_internal_value(data)
File "D:\Dev\foodgram-project-react\venv\lib\site-packages\rest_framework\serializers.py", line 492, in to_internal_value
validated_value = validate_method(validated_value)
File "D:\Dev\foodgram-project-react\backend\recipes\serializers.py", line 112, in validate_ingredients
ingredients_ids = [ingredient['id'] for ingredient in ingredients]
File "D:\Dev\foodgram-project-react\backend\recipes\serializers.py", line 112, in <listcomp>
ingredients_ids = [ingredient['id'] for ingredient in ingredients]
TypeError: string indices must be integers
That is an error in the validate_ingredients method. Please tell me how to do it right.
CodePudding user response:
Ingredients is an array, not a dictionary. ingredients[0]['id'] has sense, but ingredients['id'] not.
You can do something like this:
ingredients = data[0]
ingredients_ids = []
for ingredient in ingredients:
if not ingredient['id']:
raise ValidationError('Не выбрано ни одного ингредиента!')
else:
ingredients_ids.append(ingredient['id'])
CodePudding user response:
this solution helped:
def validate_ingredients(self, data):
ingredients = self.initial_data.get('ingredients')
if not ingredients:
raise ValidationError('Нужно выбрать минимум 1 ингридиент!')
for ingredient in ingredients:
if int(ingredient['amount']) <= 0:
raise ValidationError('Количество должно быть положительным!')
return data