TypeError: Field 'id' expected a number but got <django.contrib.auth.models.AnonymousUser object at 0x0000022009F7BF60> помогите разобраться в ошибке!
Вот вью:
from api import filters, pagination, permissions
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import mixins, status, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response
from .file import send_file
from .models import Favorite, Ingredient, Recipe, ShoppingList, Tag
from .serializers import (CreateRecipeSerializer, FavouriteSerializer,
IngredientSerializer, ReadyRecipeSerializer,
ShoppingListSerializer, TagSerializer)
class TagsViewSet(mixins.ListModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
queryset = Tag.objects.all()
serializer_class = TagSerializer
permission_classes = [AllowAny, ]
pagination_class = None
class IngredientsViewSet(mixins.ListModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
queryset = Ingredient.objects.all()
serializer_class = IngredientSerializer
permission_classes = [AllowAny, ]
filter_backends = [DjangoFilterBackend]
filterset_class = filters.IngredientFilter
pagination_class = None
class RecipeViewSet(viewsets.ModelViewSet):
queryset = Recipe.objects.all()
permission_classes = [AllowAny, ]
filter_backends = [DjangoFilterBackend]
filterset_class = filters.RecipeFilter
pagination_class = pagination.CustomPageNumberPaginator
def get_serializer_class(self):
return (
ReadyRecipeSerializer if self.request.method == 'GET' else
CreateRecipeSerializer
)
@staticmethod
def delete_method(request, pk, model):
get_object_or_404(
model,
user=request.user,
recipe=get_object_or_404(Recipe, id=pk)
).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
@staticmethod
def post_method(request, pk, serializer):
data = {'user': request.user.id, 'recipe': pk}
serializer = serializer(
data=data, context={'request': request}
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
@action(
detail=True,
methods=['POST', ],
permission_classes=[permissions.IsAuthorOrAdmin]
)
def favorite(self, request, pk):
return self.post_method(
request=request, pk=pk, serializer=FavouriteSerializer
)
@favorite.mapping.delete
def delete_favorite(self, request, pk):
return self.delete_method(request=request, pk=pk, model=Favorite)
@action(
detail=True,
methods=['POST', ],
permission_classes=[permissions.IsAuthorOrAdmin]
)
def shopping_cart(self, request, pk):
return self.post_method(
request=request, pk=pk, serializer=ShoppingListSerializer
)
@shopping_cart.mapping.delete
def delete_shopping_cart(self, request, pk):
get_object_or_404(
ShoppingList,
user=request.user,
recipe=get_object_or_404(Recipe, id=pk)
).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
@action(detail=False, permission_classes=[IsAuthenticated, ])
def download_shopping_cart(self, request):
return send_file(
request, f'Список покупок: {request.user}.txt'
)
Вот модели:
from django.contrib.auth import get_user_model
from django.core import validators
from django.db import models
User = get_user_model()
class Tag(models.Model):
name = models.CharField(
verbose_name='Тег',
unique=True,
max_length=50,
)
color = models.CharField(
verbose_name='Цвет тега',
unique=True,
max_length=50,
)
slug = models.SlugField(
verbose_name='Ссылка на тег',
unique=True,
max_length=150,
)
class Meta:
ordering = ('name',)
verbose_name = 'Тег'
verbose_name_plural = 'Теги'
def __str__(self):
return self.name
class Ingredient(models.Model):
name = models.CharField(
max_length=150,
verbose_name='Название ингредиента'
)
measurement_unit = models.CharField(
max_length=200,
verbose_name='Мера измерения'
)
class Meta:
ordering = ('name',)
verbose_name = 'Ингредиент'
verbose_name_plural = 'Ингредиенты'
def __str__(self):
return self.name
class Recipe(models.Model):
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='recipes',
verbose_name='Автор'
)
name = models.CharField(
max_length=50, verbose_name='Название'
)
image = models.ImageField(
upload_to='recipes/',
verbose_name='Изображение',
)
text = models.TextField(
max_length=1000, verbose_name='Описание рецепта'
)
ingredients = models.ManyToManyField(
Ingredient,
through='IngredientForRecipe',
verbose_name='Ингредиенты',
)
cooking_time = models.PositiveSmallIntegerField(
validators=(
validators.MinValueValidator(
1, message='Ошибка. Время не может быть меньше 1.'),
validators.MaxValueValidator(
6000, message='Ошибка. Недопустимое значение времени')
),
verbose_name='Время приготовления'
)
tags = models.ManyToManyField(
Tag,
verbose_name='Теги',
)
class Meta:
ordering = ['-id']
verbose_name = 'Рецепт'
verbose_name_plural = 'Рецепты'
def __str__(self):
return self.name
class IngredientForRecipe(models.Model):
ingredient = models.ForeignKey(
Ingredient,
on_delete=models.CASCADE,
related_name='ingredients_amounts',
)
recipe = models.ForeignKey(
Recipe,
on_delete=models.CASCADE,
related_name='ingredients_amounts',
)
amount = models.PositiveSmallIntegerField(
validators=(
validators.MinValueValidator(
1, message='Ошибка. Ингредиентов не может быть меньше 1.'),
validators.MaxValueValidator(
10000, message='Ошибка. Ингредиентов слишком много.')
),
verbose_name='Количество ингредиентов',
)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['recipe', 'ingredient'],
name='unique_recipe_ingredient',
)
]
verbose_name = 'Ингредиенты'
def __str__(self):
return f'{self.ingredient}: {self.recipe}'
class Favorite(models.Model):
user = models.ForeignKey(
User,
related_name='favorite',
on_delete=models.CASCADE)
recipe = models.ForeignKey(
Recipe,
related_name='is_favorited',
on_delete=models.CASCADE)
class Meta:
ordering = ('-id',)
verbose_name = 'Избранное'
verbose_name_plural = 'Избранное'
constraints = [
models.UniqueConstraint(
fields=['user', 'recipe'],
name='unique_favorite',
)
]
def __str__(self):
return f'{self.recipe}: {self.user}'
class ShoppingList(models.Model):
user = models.ForeignKey(
User,
related_name='purchase',
on_delete=models.CASCADE)
recipe = models.ForeignKey(
Recipe,
on_delete=models.CASCADE, )
class Meta:
verbose_name = 'Покупка'
verbose_name_plural = 'Покупки'
ordering = ('-id',)
constraints = [
models.UniqueConstraint(
fields=['user', 'recipe'],
name='unique_shopping_cart'
)
]
def __str__(self):
return f'{self.recipe}: {self.user}'
Вот сериализатор:
from django.contrib.auth import get_user_model
from django.core.validators import MinValueValidator
from drf_extra_fields.fields import Base64ImageField
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from users.serializers import CustomUserSerializer
from .models import (Favorite, Ingredient, IngredientForRecipe, Recipe,
ShoppingList, Tag)
User = get_user_model()
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ('id', 'name', 'color', 'slug')
class IngredientSerializer(serializers.ModelSerializer):
class Meta:
model = Ingredient
fields = ('id', 'name', 'measurement_unit')
class RecipeIngredientsSerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField(source='ingredient.id')
name = serializers.ReadOnlyField(source='ingredient.name')
measurement_unit = serializers.ReadOnlyField(
source='ingredient.measurement_unit'
)
class Meta:
model = IngredientForRecipe
fields = ('id', 'name', 'measurement_unit', 'amount')
class RecipeSerializer(serializers.ModelSerializer):
class Meta:
model = Recipe
fields = ('id', 'name', 'image', 'cooking_time')
class ReadyRecipeSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True, read_only=True)
author = CustomUserSerializer(read_only=True)
ingredients = serializers.SerializerMethodField()
is_favorited = serializers.SerializerMethodField()
is_in_shopping_cart = serializers.SerializerMethodField()
class Meta:
model = Recipe
fields = (
'id', 'tags', 'author',
'ingredients', 'name', 'image',
'text', 'image', 'cooking_time',
'is_favorited', 'is_in_shopping_cart'
)
def get_ingredients(self, obj):
return RecipeIngredientsSerializer(
IngredientForRecipe.objects.filter(recipe=obj), many=True
).data
def get_is_favorited(self, obj):
request = self.context.get('request')
if not request or request.user.is_anonymous:
return False
return Favorite.objects.filter(recipe=obj, user=request.user).exists()
def get_is_in_shopping_cart(self, obj):
request = self.context.get('request')
if not request or request.user.is_anonymous:
return False
return ShoppingList.objects.filter(
recipe=obj,
user=request.user
).exists()
class FavouriteSerializer(serializers.ModelSerializer):
recipe = serializers.PrimaryKeyRelatedField(queryset=Recipe.objects.all())
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = Favorite
fields = ('user', 'recipe')
def validate(self, data):
user = data['user']
recipe_id = data['recipe'].id
if Favorite.objects.filter(user=user, recipe__id=recipe_id).exists():
raise ValidationError('Рецепт уже добавлен в избранное!')
return data
def to_representation(self, instance):
return ReadyRecipeSerializer(
instance.recipe,
context={
'request': self.context.get('request')
}
).data
class ShoppingListSerializer(serializers.ModelSerializer):
recipe = serializers.PrimaryKeyRelatedField(queryset=Recipe.objects.all())
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = ShoppingList
fields = ('user', 'recipe')
def validate(self, data):
user = data['user']
recipe_id = data['recipe'].id
if ShoppingList.objects.filter(user=user,
recipe__id=recipe_id).exists():
raise ValidationError('Рецепт уже добавлен в список покупок')
return data
def to_representation(self, instance):
return ReadyRecipeSerializer(
instance.recipe,
context={
'request': self.context.get('request')
}
).data
class CreateIngredientsForRecipeSerializers(serializers.ModelSerializer):
id = serializers.PrimaryKeyRelatedField(queryset=Ingredient.objects.all())
amount = serializers.IntegerField()
class Meta:
model = IngredientForRecipe
fields = ('id', 'amount')
class CreateRecipeSerializer(serializers.ModelSerializer):
image = Base64ImageField()
author = serializers.PrimaryKeyRelatedField(
default=serializers.CurrentUserDefault(), read_only=True
)
ingredients = CreateIngredientsForRecipeSerializers(many=True)
tags = serializers.PrimaryKeyRelatedField(
queryset=Tag.objects.all(), many=True
)
cooking_time = serializers.IntegerField(
validators=(MinValueValidator(1, 'Время не может быть меньше 1'),)
)
class Meta:
model = Recipe
fields = (
'id', 'author', 'ingredients',
'tags', 'image', 'name',
'text', 'cooking_time')
@staticmethod
def create_ingredients(ingredients, recipe):
for ingredient in ingredients:
IngredientForRecipe.objects.create(
recipe=recipe,
ingredient=ingredient['id'],
amount=ingredient['amount']
)
@staticmethod
def create_tags(tags, recipe):
for tag in tags:
recipe.tags.add(tag)
def validate(self, data):
ingredients = self.initial_data.get('ingredients')
ingredients_list = []
tags = self.initial_data.get('tags')
tags_list = []
if not ingredients:
raise ValidationError('Не выбраны ингредиенты')
for ingredient in ingredients:
if int(ingredient['amount']) <= 0:
raise ValidationError(
f'{ingredient} указано не допустимое кол-во ингредиентов :'
f'{ingredient["amount"]}'
)
if ingredient['id'] in ingredients_list:
raise serializers.ValidationError(
'Ингредиенты не должны повторяться'
)
ingredients_list.append(ingredient['id'])
for tag in tags:
if tag in tags_list:
raise serializers.ValidationError(
'Теги не должны повторяться'
)
tags_list.append(tag)
return data
def create(self, validated_data):
author = self.context.get('request').user
ingredients = validated_data.pop('ingredients')
tags = validated_data.pop('tags')
recipe = Recipe.objects.create(author=author, **validated_data)
self.create_tags(tags, recipe)
self.create_ingredients(ingredients, recipe)
return recipe
def update(self, instance, validated_data):
instance.tags.clear()
IngredientForRecipe.objects.filter(recipe=instance).all().delete()
self.create_tags(validated_data.pop('tags'), instance)
self.create_ingredients(validated_data.pop('ingredients'), instance)
return super().update(instance, validated_data)
def to_representation(self, instance):
return ReadyRecipeSerializer(
instance,
context={
'request': self.context.get('request')
}
).data
Если что, могу скинуть ссылку на репозиторий в гитхабе.
Ошибка возникает при GET запросе:
http://127.0.0.1:8000/api/recipes/?page=1&limit=6&is_favorited=1