diff --git a/README.md b/README.md index 50825e5..5b65c09 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,11 @@ REST API with Python, Django REST Framework and Docker using Test Driven Develop * Delete ingredient - Recipe Image API * Upload image to recipe +- Filter recipes by tags and ingredients + - How to use: + - `/api/recipes/?tags=` + - `/api/recipes/?ingredients=` + ## Documentation The API documentation is created using [drf-spectacular](https://drf-spectacular.readthedocs.io/en/latest/). diff --git a/app/recipe/views.py b/app/recipe/views.py index f132fdd..94a4aa6 100644 --- a/app/recipe/views.py +++ b/app/recipe/views.py @@ -1,7 +1,12 @@ """ Views for the recipe APIs. """ -from drf_spectacular.utils import extend_schema, extend_schema_view +from drf_spectacular.utils import ( + extend_schema_view, + extend_schema, + OpenApiParameter, + OpenApiTypes, +) from rest_framework import viewsets, mixins, status from rest_framework.decorators import action @@ -18,6 +23,18 @@ list=extend_schema( summary='Retrieve a list of recipes', description='Retrieve a list of recipes for the authenticated user.', + parameters=[ + OpenApiParameter( + 'tags', + OpenApiTypes.STR, + description='Comma separated list of tags IDs to filter', + ), + OpenApiParameter( + 'ingredients', + OpenApiTypes.STR, + description='Comma separated list of ingredients IDs to filter' + ), + ] ), create=extend_schema( summary='Create a new recipe', @@ -47,9 +64,29 @@ class RecipeViewSet(viewsets.ModelViewSet): 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.""" - return self.queryset.filter(user=self.request.user).order_by('-id') + # retrieve query params provided as string of comma separated values + tags = self.request.query_params.get('tags') + ingredients = self.request.query_params.get('ingredients') + queryset = self.queryset + + # filter queryset based on query params + if tags: + tag_ids = self._params_to_ints(tags) + queryset = queryset.filter(tags__id__in=tag_ids) + if ingredients: + ingredient_ids = self._params_to_ints(ingredients) + queryset = queryset.filter(ingredients__id__in=ingredient_ids) + + # return filtered queryset for authenticated user + return queryset.filter( + user=self.request.user + ).order_by('-id').distinct() def get_serializer_class(self): """Return the serializer class for request."""