From d72c3947d4ce3cf2dd433cb046bcae0480dfb5c8 Mon Sep 17 00:00:00 2001 From: Egor fureunoir Gorbunov Date: Thu, 19 Jun 2025 09:42:02 +0300 Subject: [PATCH] Features: 1) Ensure querysets return distinct results in filters; Fixes: 1) Address potential duplication issue in querysets; Extra: --- core/filters.py | 110 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 24 deletions(-) diff --git a/core/filters.py b/core/filters.py index e3f1f752..ea2ef71c 100644 --- a/core/filters.py +++ b/core/filters.py @@ -48,19 +48,31 @@ class CaseInsensitiveListFilter(BaseInFilter, CharFilter): class ProductFilter(FilterSet): uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID")) name = CharFilter(field_name="name", lookup_expr="icontains", label=_("Name")) - categories = CaseInsensitiveListFilter(field_name="category__name", label=_("Categories")) + categories = CaseInsensitiveListFilter( + field_name="category__name", label=_("Categories") + ) category_uuid = CharFilter(method="filter_category", label="Category (UUID)") - categories_slugs = CaseInsensitiveListFilter(field_name="category__slug", label=_("Categories Slugs")) + categories_slugs = CaseInsensitiveListFilter( + field_name="category__slug", label=_("Categories Slugs") + ) tags = CaseInsensitiveListFilter(field_name="tags__tag_name", label=_("Tags")) - min_price = NumberFilter(field_name="stocks__price", lookup_expr="gte", label=_("Min Price")) - max_price = NumberFilter(field_name="stocks__price", lookup_expr="lte", label=_("Max Price")) + min_price = NumberFilter( + field_name="stocks__price", lookup_expr="gte", label=_("Min Price") + ) + max_price = NumberFilter( + field_name="stocks__price", lookup_expr="lte", label=_("Max Price") + ) is_active = BooleanFilter(field_name="is_active", label=_("Is Active")) brand = CharFilter(field_name="brand__name", lookup_expr="iexact", label=_("Brand")) attributes = CharFilter(method="filter_attributes", label=_("Attributes")) - quantity = NumberFilter(field_name="stocks__quantity", lookup_expr="gt", label=_("Quantity")) + quantity = NumberFilter( + field_name="stocks__quantity", lookup_expr="gt", label=_("Quantity") + ) slug = CharFilter(field_name="slug", lookup_expr="exact", label=_("Slug")) is_digital = BooleanFilter(field_name="is_digital", label=_("Is Digital")) - include_subcategories = BooleanFilter(method="filter_include_flag", label=_("Include sub-categories")) + include_subcategories = BooleanFilter( + method="filter_include_flag", label=_("Include sub-categories") + ) order_by = OrderingFilter( fields=( @@ -111,13 +123,16 @@ class ProductFilter(FilterSet): ) self.queryset = self.queryset.annotate( rating=Coalesce( - Subquery(feedback_qs, output_field=FloatField()), Value(0, output_field=FloatField()) + Subquery(feedback_qs, output_field=FloatField()), + Value(0, output_field=FloatField()), ) ) def filter_include_flag(self, queryset, **_kwargs): if not self.data.get("category_uuid"): - raise BadRequest(_("there must be a category_uuid to use include_subcategories flag")) + raise BadRequest( + _("there must be a category_uuid to use include_subcategories flag") + ) return queryset def filter_attributes(self, queryset, _name, value): @@ -240,7 +255,8 @@ class ProductFilter(FilterSet): ) qs = qs.annotate( rating=Coalesce( - Subquery(feedback_qs, output_field=FloatField()), Value(0, output_field=FloatField()) + Subquery(feedback_qs, output_field=FloatField()), + Value(0, output_field=FloatField()), ) ) return qs.distinct() @@ -252,14 +268,26 @@ class OrderFilter(FilterSet): label=_("Search (ID, product name or part number)"), ) - min_buy_time = DateTimeFilter(field_name="buy_time", lookup_expr="gte", label=_("Bought after (inclusive)")) - max_buy_time = DateTimeFilter(field_name="buy_time", lookup_expr="lte", label=_("Bought before (inclusive)")) + min_buy_time = DateTimeFilter( + field_name="buy_time", lookup_expr="gte", label=_("Bought after (inclusive)") + ) + max_buy_time = DateTimeFilter( + field_name="buy_time", lookup_expr="lte", label=_("Bought before (inclusive)") + ) uuid = UUIDFilter(field_name="uuid", lookup_expr="exact") - user_email = CharFilter(field_name="user__email", lookup_expr="iexact", label=_("User email")) - user = UUIDFilter(field_name="user__uuid", lookup_expr="exact", label=_("User UUID")) + user_email = CharFilter( + field_name="user__email", lookup_expr="iexact", label=_("User email") + ) + user = UUIDFilter( + field_name="user__uuid", lookup_expr="exact", label=_("User UUID") + ) status = CharFilter(field_name="status", lookup_expr="icontains", label=_("Status")) - human_readable_id = CharFilter(field_name="human_readable_id", lookup_expr="exact", label=_("Human Readable ID")) + human_readable_id = CharFilter( + field_name="human_readable_id", + lookup_expr="exact", + label=_("Human Readable ID"), + ) order_by = OrderingFilter( fields=( @@ -299,11 +327,20 @@ class OrderFilter(FilterSet): class WishlistFilter(FilterSet): uuid = UUIDFilter(field_name="uuid", lookup_expr="exact") - user_email = CharFilter(field_name="user__email", lookup_expr="iexact", label=_("User email")) - user = UUIDFilter(field_name="user__uuid", lookup_expr="exact", label=_("User UUID")) + user_email = CharFilter( + field_name="user__email", lookup_expr="iexact", label=_("User email") + ) + user = UUIDFilter( + field_name="user__uuid", lookup_expr="exact", label=_("User UUID") + ) order_by = OrderingFilter( - fields=(("uuid", "uuid"), ("created", "created"), ("modified", "modified"), ("?", "random")) + fields=( + ("uuid", "uuid"), + ("created", "created"), + ("modified", "modified"), + ("?", "random"), + ) ) class Meta: @@ -317,7 +354,9 @@ class CategoryFilter(FilterSet): parent_uuid = CharFilter(method="filter_parent_uuid", label=_("Parent")) slug = CharFilter(field_name="slug", lookup_expr="exact", label=_("Slug")) whole = BooleanFilter( - field_name="whole", label=_("Whole category(has at least 1 product or not)"), method="filter_whole_categories" + field_name="whole", + label=_("Whole category(has at least 1 product or not)"), + method="filter_whole_categories", ) tags = CaseInsensitiveListFilter(field_name="tags__tag_name", label=_("Tags")) level = NumberFilter(field_name="level", lookup_expr="exact", label=_("Level")) @@ -332,7 +371,16 @@ class CategoryFilter(FilterSet): class Meta: model = Category - fields = ["uuid", "name", "parent_uuid", "slug", "tags", "level", "order_by", "whole"] + fields = [ + "uuid", + "name", + "parent_uuid", + "slug", + "tags", + "level", + "order_by", + "whole", + ] def filter_whole_categories(self, queryset, _name, value): has_own_products = Exists(Product.objects.filter(category=OuterRef("pk"))) @@ -364,7 +412,9 @@ class CategoryFilter(FilterSet): class BrandFilter(FilterSet): uuid = UUIDFilter(field_name="uuid", lookup_expr="exact") name = CharFilter(field_name="name", lookup_expr="icontains", label=_("Name")) - categories = CaseInsensitiveListFilter(field_name="categories__uuid", lookup_expr="exact", label=_("Categories")) + categories = CaseInsensitiveListFilter( + field_name="categories__uuid", lookup_expr="exact", label=_("Categories") + ) order_by = OrderingFilter( fields=( @@ -381,8 +431,16 @@ class BrandFilter(FilterSet): class FeedbackFilter(FilterSet): uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID")) - product_uuid = UUIDFilter(field_name="order_product__product__uuid", lookup_expr="exact", label=_("Product UUID")) - user_uuid = UUIDFilter(field_name="order_product__order__user__uuid", lookup_expr="exact", label=_("User UUID")) + product_uuid = UUIDFilter( + field_name="order_product__product__uuid", + lookup_expr="exact", + label=_("Product UUID"), + ) + user_uuid = UUIDFilter( + field_name="order_product__order__user__uuid", + lookup_expr="exact", + label=_("User UUID"), + ) order_by = OrderingFilter( fields=( @@ -402,8 +460,12 @@ class FeedbackFilter(FilterSet): class AddressFilter(FilterSet): uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID")) - user_uuid = UUIDFilter(field_name="user__uuid", lookup_expr="exact", label=_("User UUID")) - user_email = CharFilter(field_name="user__email", lookup_expr="iexact", label=_("User email")) + user_uuid = UUIDFilter( + field_name="user__uuid", lookup_expr="exact", label=_("User UUID") + ) + user_email = CharFilter( + field_name="user__email", lookup_expr="iexact", label=_("User email") + ) order_by = OrderingFilter( fields=(