Home > Mobile >  Error "string indices must be integers" when querying
Error "string indices must be integers" when querying

Time:03-09

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
  • Related