From 658e7990762b99cfb28a33b1f2da7e948f1e209e Mon Sep 17 00:00:00 2001 From: Egor fureunoir Gorbunov Date: Thu, 19 Jun 2025 10:49:56 +0300 Subject: [PATCH] Features: 1) Add ordered filtering logic for `filter_name` methods across products, categories, and brands; 2) Enhance query processing with `Case` and `When` operations for precise ordering; Fixes: 1) Ensure queryset returns `none()` when no valid UUIDs are found in filters; Extra: 1) Refactor import statements for readability; 2) Clean up and consolidate redundant filter logic across multiple `filter_name` methods; --- core/filters.py | 79 +++++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/core/filters.py b/core/filters.py index bc9929c4..35076d9e 100644 --- a/core/filters.py +++ b/core/filters.py @@ -3,7 +3,18 @@ import logging import uuid from django.core.exceptions import BadRequest -from django.db.models import Avg, Exists, FloatField, OuterRef, Q, Subquery, Value +from django.db.models import ( + Avg, + Case, + Exists, + FloatField, + IntegerField, + OuterRef, + Q, + Subquery, + Value, + When, +) from django.db.models.functions import Coalesce from django.utils.http import urlsafe_base64_decode from django.utils.translation import gettext_lazy as _ @@ -131,15 +142,19 @@ class ProductFilter(FilterSet): def filter_name(self, queryset, _name, value): search_results = process_query(query=value, request=self.request)["products"] - if search_results: - queryset = queryset.filter( - uuid__in=[ - result.get("uuid") - for result in search_results - if result.get("uuid") is not None - ] - ) - return queryset + uuids = [res["uuid"] for res in search_results if res.get("uuid")] + + if not uuids: + return queryset.none() + + ordering = Case( + *[When(uuid=uuid_, then=pos) for pos, uuid_ in enumerate(uuids)], + output_field=IntegerField(), + ) + + return ( + queryset.filter(uuid__in=uuids).annotate(_order=ordering).order_by("_order") + ) def filter_include_flag(self, queryset, **_kwargs): if not self.data.get("category_uuid"): @@ -397,15 +412,19 @@ class CategoryFilter(FilterSet): def filter_name(self, queryset, _name, value): search_results = process_query(query=value, request=self.request)["categories"] - if search_results: - queryset = queryset.filter( - uuid__in=[ - result.get("uuid") - for result in search_results - if result.get("uuid") is not None - ] - ) - return queryset + uuids = [res["uuid"] for res in search_results if res.get("uuid")] + + if not uuids: + return queryset.none() + + ordering = Case( + *[When(uuid=uuid_, then=pos) for pos, uuid_ in enumerate(uuids)], + output_field=IntegerField(), + ) + + return ( + queryset.filter(uuid__in=uuids).annotate(_order=ordering).order_by("_order") + ) def filter_whole_categories(self, queryset, _name, value): has_own_products = Exists(Product.objects.filter(category=OuterRef("pk"))) @@ -455,15 +474,19 @@ class BrandFilter(FilterSet): def filter_name(self, queryset, _name, value): search_results = process_query(query=value, request=self.request)["brands"] - if search_results: - queryset = queryset.filter( - uuid__in=[ - result.get("uuid") - for result in search_results - if result.get("uuid") is not None - ] - ) - return queryset + uuids = [res["uuid"] for res in search_results if res.get("uuid")] + + if not uuids: + return queryset.none() + + ordering = Case( + *[When(uuid=uuid_, then=pos) for pos, uuid_ in enumerate(uuids)], + output_field=IntegerField(), + ) + + return ( + queryset.filter(uuid__in=uuids).annotate(_order=ordering).order_by("_order") + ) class FeedbackFilter(FilterSet):