diff --git a/backend/api/serializers.py b/backend/api/serializers.py index 12abf59..3cb8e88 100644 --- a/backend/api/serializers.py +++ b/backend/api/serializers.py @@ -95,7 +95,7 @@ class Meta: 'recipes', 'recipes_count', ) - read_only_fields = ('__all__',) + read_only_fields = '__all__' @staticmethod def get_recipes_count(obj): @@ -108,7 +108,7 @@ class TagSerializer(ModelSerializer): class Meta: model = Tag fields = '__all__' - read_only_fields = ('__all__',) + read_only_fields = '__all__' class IngredientSearchSerializer(ModelSerializer): @@ -117,7 +117,7 @@ class IngredientSearchSerializer(ModelSerializer): class Meta: model = Ingredient fields = '__all__' - read_only_fields = ('__all__',) + read_only_fields = '__all__' class IngredientSerializer(ModelSerializer): diff --git a/backend/api/validators.py b/backend/api/validators.py index 09a8739..249b6f4 100644 --- a/backend/api/validators.py +++ b/backend/api/validators.py @@ -1,10 +1,8 @@ from django.core.exceptions import ValidationError -from django.conf import settings - -MIN_INGREDIENT_AMOUNT = settings.MIN_INGREDIENT_AMOUNT -MAX_INGREDIENT_AMOUNT = settings.MAX_INGREDIENT_AMOUNT -MIN_COOKING_TIME = settings.MIN_COOKING_TIME -MAX_COOKING_TIME = settings.MAX_COOKING_TIME +from foodgram.settings import (MIN_INGR_AMOUNT, + MAX_INGR_AMOUNT, + MAX_COOK_TIME, + MIN_COOK_TIME) def ingredients_validator(ingredients): @@ -25,12 +23,11 @@ def ingredients_validator(ingredients): ingredient_names.add(name) - if not MIN_INGREDIENT_AMOUNT <= amount <= MAX_INGREDIENT_AMOUNT: + if not MIN_INGR_AMOUNT <= amount <= MAX_INGR_AMOUNT: raise ValidationError({ 'amount': [ - 'Количество ингредиента должно быть от {} до {}.'.format( - MIN_INGREDIENT_AMOUNT, MAX_INGREDIENT_AMOUNT - ) + f'Количество ингредиента должно быть от {MIN_INGR_AMOUNT} ' + f'до {MAX_INGR_AMOUNT}.' ] }) @@ -39,15 +36,12 @@ def ingredients_validator(ingredients): def cooking_time_validator(cooking_time): """ - Валидирует суммарное время готовки. - - Проверяет минимальное и максимальное время готовки. + Валидирует минимальное и максимальное время готовки. """ - if not MIN_COOKING_TIME <= cooking_time <= MAX_COOKING_TIME: + if not MIN_COOK_TIME <= cooking_time <= MAX_COOK_TIME: raise ValidationError({ 'cooking_time': [ - 'Время приготовления должно быть от {} до {} минут.'.format( - MIN_COOKING_TIME, MAX_COOKING_TIME - ) + f'Время приготовления должно быть от {MIN_COOK_TIME} ' + f'до {MAX_COOK_TIME} минут.' ] }) diff --git a/backend/api/views.py b/backend/api/views.py index d7b64f0..c3afd38 100644 --- a/backend/api/views.py +++ b/backend/api/views.py @@ -38,7 +38,6 @@ def get_permissions(self): class CustomUserViewSet(UserViewSet, AddDeleteMixin): pagination_class = PageNumberPagination queryset = CustomUser.objects.all() - serializer_class = CustomUserSerializer def get_serializer_class(self): if self.action == 'set_password': @@ -102,7 +101,7 @@ class TagViewSet(BasePermissionViewSet): class RecipeViewSet(viewsets.ModelViewSet, AddDeleteMixin): - queryset = Recipe.objects.all().order_by('-id') + queryset = Recipe.objects.all() pagination_class = PageNumberPagination permission_classes = (AuthorOrReadOnly,) filter_backends = (DjangoFilterBackend,) @@ -188,9 +187,10 @@ def download_shopping_cart_list(self, request): } # Создаем динамический файл TXT - filename = settings.SHOPPING_LIST_FILENAME response = HttpResponse(content_type=settings.CONTENT_TYPE) - response['Content-Disposition'] = f'attachment; filename={filename}' + response['Content-Disposition'] = ( + f'attachment; filename={settings.SHOPPING_LIST_FILENAME}' + ) response.write('Ингредиент, Количество, Единица измерения:\n') diff --git a/backend/foodgram/settings.py b/backend/foodgram/settings.py index 372c3e1..a8bd91f 100644 --- a/backend/foodgram/settings.py +++ b/backend/foodgram/settings.py @@ -81,10 +81,10 @@ } } -MIN_INGREDIENT_AMOUNT = 1 -MAX_INGREDIENT_AMOUNT = 100 -MIN_COOKING_TIME = 1 -MAX_COOKING_TIME = 600 +MIN_INGR_AMOUNT = 1 +MAX_INGR_AMOUNT = 100 +MIN_COOK_TIME = 1 +MAX_COOK_TIME = 600 SHOPPING_LIST_FILENAME = 'shopping_list.txt' CONTENT_TYPE = 'text/plain' @@ -153,4 +153,4 @@ AUTH_USER_MODEL = 'users.CustomUser' -LANGUAGE_CODE = "ru" +LANGUAGE_CODE = 'ru' diff --git a/backend/recipes/admin.py b/backend/recipes/admin.py index 8dd5cb8..aec2ebb 100644 --- a/backend/recipes/admin.py +++ b/backend/recipes/admin.py @@ -19,7 +19,7 @@ class RecipesAdmin(AdminPermissions): list_display = ('name', 'author', 'favorite_count') list_filter = ('author', 'name', 'tags') search_fields = ('name', 'author__username') - inlines = [IngredientsAmountInline] + inlines = (IngredientsAmountInline,) readonly_fields = ('favorite_count',) def get_queryset(self, request): diff --git a/backend/recipes/models.py b/backend/recipes/models.py index bb7aa7d..943e917 100644 --- a/backend/recipes/models.py +++ b/backend/recipes/models.py @@ -1,5 +1,11 @@ from django.db import models +from django.core.validators import MinValueValidator, MaxValueValidator + from users.models import CustomUser +from foodgram.settings import (MIN_COOK_TIME, + MAX_COOK_TIME, + MAX_INGR_AMOUNT, + MIN_INGR_AMOUNT) class Tag(models.Model): @@ -86,7 +92,17 @@ class Recipe(models.Model): related_name='recipes', ) cooking_time = models.PositiveSmallIntegerField( - verbose_name='Время приготовления (в минутах)' + verbose_name='Время приготовления (в минутах)', + validators=[ + MinValueValidator(limit_value=MIN_COOK_TIME, + message=f'Время приготовления ' + f'должно быть не менее ' + f'{MIN_COOK_TIME}! минуты'), + MaxValueValidator(limit_value=MAX_COOK_TIME, + message=f'Время приготовления ' + f'должно быть не более ' + f'{MAX_COOK_TIME} минут!'), + ] ) pub_date = models.DateTimeField( verbose_name='Дата публикации', @@ -124,6 +140,16 @@ class IngredientsAmount(models.Model): ) amount = models.PositiveSmallIntegerField( verbose_name='Количество', + validators=[ + MinValueValidator(limit_value=MIN_INGR_AMOUNT, + message=f'Количество ингредиента ' + f'должно быть не менее ' + f'{MIN_INGR_AMOUNT}!'), + MaxValueValidator(limit_value=MAX_INGR_AMOUNT, + message=f'Количество ингредиента ' + f'должно быть не более ' + f'{MAX_INGR_AMOUNT}!'), + ], default=0, ) diff --git a/backend/users/models.py b/backend/users/models.py index 5ae60bb..022d382 100644 --- a/backend/users/models.py +++ b/backend/users/models.py @@ -21,7 +21,7 @@ class CustomUser(AbstractUser): email = models.EmailField( verbose_name='Адрес электронной почты', max_length=254, - validators=[validate_email], + validators=(validate_email,), unique=True) password = models.CharField( verbose_name='Пароль', @@ -29,7 +29,7 @@ class CustomUser(AbstractUser): ) class Meta: - ordering = ['username'] + ordering = 'username' verbose_name = 'Пользователь' verbose_name_plural = 'Пользователи'