2023-10-09 03:25:09 -03:00
|
|
|
"""
|
|
|
|
Views for the recipe APIs.
|
|
|
|
"""
|
2023-10-12 00:44:46 -03:00
|
|
|
from drf_spectacular.utils import (
|
|
|
|
extend_schema_view,
|
|
|
|
extend_schema,
|
|
|
|
OpenApiParameter,
|
|
|
|
)
|
|
|
|
from drf_spectacular.types import OpenApiTypes
|
2023-10-10 00:08:52 -03:00
|
|
|
from rest_framework import (
|
|
|
|
viewsets,
|
|
|
|
mixins,
|
2023-10-11 17:59:44 -03:00
|
|
|
status,
|
2023-10-10 00:08:52 -03:00
|
|
|
)
|
2023-10-11 17:59:44 -03:00
|
|
|
from rest_framework.decorators import action
|
|
|
|
from rest_framework.response import Response
|
2023-10-09 03:25:09 -03:00
|
|
|
from rest_framework.authentication import TokenAuthentication
|
|
|
|
from rest_framework.permissions import IsAuthenticated
|
|
|
|
|
2023-10-10 00:08:52 -03:00
|
|
|
from core.models import (
|
2023-10-11 01:05:54 -03:00
|
|
|
Ingredient,
|
2023-10-10 00:08:52 -03:00
|
|
|
Recipe,
|
|
|
|
Tag,
|
|
|
|
)
|
2023-10-09 03:25:09 -03:00
|
|
|
from recipe import serializers
|
|
|
|
|
|
|
|
|
2023-10-12 00:44:46 -03:00
|
|
|
@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'
|
|
|
|
),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
)
|
2023-10-09 03:25:09 -03:00
|
|
|
class RecipeViewSet(viewsets.ModelViewSet):
|
|
|
|
"""View for manage recipe APIs."""
|
2023-10-09 15:34:58 -03:00
|
|
|
serializer_class = serializers.RecipeDetailSerializer
|
2023-10-09 03:25:09 -03:00
|
|
|
queryset = Recipe.objects.all()
|
|
|
|
authentication_classes = [TokenAuthentication]
|
|
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
|
2023-10-12 00:44:46 -03:00
|
|
|
def _params_to_ints(self, qs):
|
|
|
|
"""Convert a list of strings to integers."""
|
|
|
|
return [int(str_id) for str_id in qs.split(',')]
|
|
|
|
|
2023-10-09 03:25:09 -03:00
|
|
|
def get_queryset(self):
|
|
|
|
"""Retrieve recipes for authenticated user."""
|
2023-10-12 00:44:46 -03:00
|
|
|
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()
|
2023-10-09 15:34:58 -03:00
|
|
|
|
|
|
|
def get_serializer_class(self):
|
|
|
|
"""Return the serializer class for request."""
|
|
|
|
if self.action == 'list':
|
|
|
|
return serializers.RecipeSerializer
|
2023-10-11 17:59:44 -03:00
|
|
|
elif self.action == 'upload_image':
|
|
|
|
return serializers.RecipeImageSerializer
|
|
|
|
|
2023-10-09 15:34:58 -03:00
|
|
|
return self.serializer_class
|
|
|
|
|
|
|
|
def perform_create(self, serializer):
|
|
|
|
"""Create a new recipe."""
|
|
|
|
serializer.save(user=self.request.user)
|
2023-10-10 00:08:52 -03:00
|
|
|
|
2023-10-11 17:59:44 -03:00
|
|
|
@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)
|
|
|
|
|
2023-10-10 00:08:52 -03:00
|
|
|
|
2023-10-12 00:44:46 -03:00
|
|
|
@extend_schema_view(
|
|
|
|
list=extend_schema(
|
|
|
|
parameters=[
|
|
|
|
OpenApiParameter(
|
|
|
|
'assigned_only',
|
|
|
|
OpenApiTypes.INT, enum=[0, 1],
|
|
|
|
description='Filtro por items asignados a recetas.'
|
|
|
|
),
|
|
|
|
]
|
|
|
|
)
|
|
|
|
)
|
2023-10-11 01:05:54 -03:00
|
|
|
class BaseRecipeAtrrViewSet(mixins.DestroyModelMixin,
|
|
|
|
mixins.UpdateModelMixin,
|
|
|
|
mixins.ListModelMixin,
|
|
|
|
viewsets.GenericViewSet):
|
|
|
|
"""Base viewset for recipe attributes."""
|
2023-10-10 00:08:52 -03:00
|
|
|
authentication_classes = [TokenAuthentication]
|
|
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
"""Filter queryset to authenticated user."""
|
2023-10-12 00:44:46 -03:00
|
|
|
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()
|
2023-10-11 01:05:54 -03:00
|
|
|
|
|
|
|
|
|
|
|
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()
|