recipes_api/app/recipe/views.py

141 lines
4.3 KiB
Python

"""
Views for the recipe APIs.
"""
from drf_spectacular.utils import (
extend_schema_view,
extend_schema,
OpenApiParameter,
)
from drf_spectacular.types import OpenApiTypes
from rest_framework import (
viewsets,
mixins,
status,
)
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
from core.models import (
Ingredient,
Recipe,
Tag,
)
from recipe import serializers
@extend_schema_view(
list=extend_schema(
parameters=[
OpenApiParameter(
'tags',
OpenApiTypes.STR,
description='Lista separada por coma de tags IDs a filtrar'
),
OpenApiParameter(
'ingredients',
OpenApiTypes.STR,
description='Lista separada por coma de ingredientes IDs a \
filtrar'
),
]
)
)
class RecipeViewSet(viewsets.ModelViewSet):
"""View for manage recipe APIs."""
serializer_class = serializers.RecipeDetailSerializer
queryset = Recipe.objects.all()
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def _params_to_ints(self, qs):
"""Convert a list of strings to integers."""
return [int(str_id) for str_id in qs.split(',')]
def get_queryset(self):
"""Retrieve recipes for authenticated user."""
tags = self.request.query_params.get('tags')
ingredients = self.request.query_params.get('ingredients')
queryset = self.queryset
if tags:
tag_ids = self._params_to_ints(tags)
queryset = queryset.filter(tags__id__in=tag_ids)
if ingredients:
ingredients_ids = self._params_to_ints(ingredients)
queryset = queryset.filter(ingredients__id__in=ingredients_ids)
return queryset.filter(
user=self.request.user
).order_by('-id').distinct()
def get_serializer_class(self):
"""Return the serializer class for request."""
if self.action == 'list':
return serializers.RecipeSerializer
elif self.action == 'upload_image':
return serializers.RecipeImageSerializer
return self.serializer_class
def perform_create(self, serializer):
"""Create a new recipe."""
serializer.save(user=self.request.user)
@action(methods=['POST'], detail=True, url_path='upload-image')
def upload_image(self, request, pk=None):
"""Upload an image to recipe."""
recipe = self.get_object()
serializer = self.get_serializer(recipe, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@extend_schema_view(
list=extend_schema(
parameters=[
OpenApiParameter(
'assigned_only',
OpenApiTypes.INT, enum=[0, 1],
description='Filtro por items asignados a recetas.'
),
]
)
)
class BaseRecipeAtrrViewSet(mixins.DestroyModelMixin,
mixins.UpdateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
"""Base viewset for recipe attributes."""
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get_queryset(self):
"""Filter queryset to authenticated user."""
assigned_only = bool(
int(self.request.query_params.get('assigned_only', 0))
)
queryset = self.queryset
if assigned_only:
queryset = queryset.filter(recipe__isnull=False)
return queryset.filter(
user=self.request.user
).order_by('-name').distinct()
class TagViewSet(BaseRecipeAtrrViewSet):
"""Manage tags in the database."""
serializer_class = serializers.TagSerializer
queryset = Tag.objects.all()
class IngredientViewSet(BaseRecipeAtrrViewSet):
"""Manage ingredients in the database."""
serializer_class = serializers.IngredientSerializer
queryset = Ingredient.objects.all()