From f6f334f5d7affe4e032d1c4647269f8614aff63d Mon Sep 17 00:00:00 2001 From: oguzpancuk <44545164+oguzpancuk@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:06:12 +0300 Subject: [PATCH 1/2] Implemented post search with multiple tags A new endpoint for searching posts with multiple tags is implemented --- backend/marketfeed/views.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/backend/marketfeed/views.py b/backend/marketfeed/views.py index 922aa25b..2edc91af 100644 --- a/backend/marketfeed/views.py +++ b/backend/marketfeed/views.py @@ -14,7 +14,8 @@ import yfinance as yf from concurrent.futures import ThreadPoolExecutor from django.db.models import Q -from drf_spectacular.utils import extend_schema, OpenApiParameter +from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes + @@ -350,6 +351,37 @@ def posts_by_tag(self, request, tag_id=None): serializer = PostSerializer(queryset, many=True) return Response(serializer.data) + @extend_schema( + parameters=[ + OpenApiParameter( + name='tags', + type=OpenApiTypes.STR, + location=OpenApiParameter.PATH, + description='Comma-separated list of tag IDs (e.g., 1,2,3)', + required=True, + ) + ] + ) + @action(detail=False, methods=['get'], url_path='posts-by-tags/(?P[^/.]+)') + def posts_by_tags(self, request, tags=None): + """ + Retrieve posts by multiple tag IDs (comma-separated in the `tags` path parameter). + """ + if not tags: + return Response({'detail': 'No tags provided.'}, status=status.HTTP_400_BAD_REQUEST) + + try: + tag_ids = [int(tag_id.strip()) for tag_id in tags.split(',') if tag_id.strip().isdigit()] + except ValueError: + return Response({'detail': 'Invalid tag IDs provided.'}, status=status.HTTP_400_BAD_REQUEST) + + tags = Tag.objects.filter(id__in=tag_ids) + if not tags.exists(): + return Response({'detail': 'No posts found for the specified tags.'}, status=status.HTTP_404_NOT_FOUND) + + posts = Post.objects.filter(tags__in=tags).distinct() + serializer = self.get_serializer(posts, many=True) + return Response(serializer.data, status=status.HTTP_200_OK) class CommentViewSet(viewsets.ModelViewSet): queryset = Comment.objects.all() From 0d47ed6336e01c42f92db5ff35cb4f2aa428def9 Mon Sep 17 00:00:00 2001 From: oguzpancuk <44545164+oguzpancuk@users.noreply.github.com> Date: Sun, 15 Dec 2024 18:36:41 +0300 Subject: [PATCH 2/2] Added functionality to search posts by tags with "and" or "or" Get method now takes one additional parameter ("and" or default "or" behaviour) and performs the query accordingly. --- backend/marketfeed/views.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/backend/marketfeed/views.py b/backend/marketfeed/views.py index 2edc91af..4e49413a 100644 --- a/backend/marketfeed/views.py +++ b/backend/marketfeed/views.py @@ -359,14 +359,18 @@ def posts_by_tag(self, request, tag_id=None): location=OpenApiParameter.PATH, description='Comma-separated list of tag IDs (e.g., 1,2,3)', required=True, + ), + OpenApiParameter( + name='type', + type=OpenApiTypes.STR, + location=OpenApiParameter.QUERY, + description='Type of filter: "and" (all tags) or "or" (at least one tag)', + required=False, ) ] ) @action(detail=False, methods=['get'], url_path='posts-by-tags/(?P[^/.]+)') def posts_by_tags(self, request, tags=None): - """ - Retrieve posts by multiple tag IDs (comma-separated in the `tags` path parameter). - """ if not tags: return Response({'detail': 'No tags provided.'}, status=status.HTTP_400_BAD_REQUEST) @@ -379,7 +383,16 @@ def posts_by_tags(self, request, tags=None): if not tags.exists(): return Response({'detail': 'No posts found for the specified tags.'}, status=status.HTTP_404_NOT_FOUND) - posts = Post.objects.filter(tags__in=tags).distinct() + filter_type = request.query_params.get('type', 'or').lower() + + if filter_type == 'and': + # Posts that have all the specified tags + for tag in tags: + posts = Post.objects.filter(tags=tag) if 'posts' not in locals() else posts.filter(tags=tag) + else: # Default to "or" behavior + # Posts that have at least one of the specified tags + posts = Post.objects.filter(tags__in=tags).distinct() + serializer = self.get_serializer(posts, many=True) return Response(serializer.data, status=status.HTTP_200_OK)