Features: 1) Ensure querysets return distinct results in filters;
Fixes: 1) Address potential duplication issue in querysets; Extra:
This commit is contained in:
parent
d40d7d3c28
commit
d72c3947d4
1 changed files with 86 additions and 24 deletions
110
core/filters.py
110
core/filters.py
|
|
@ -48,19 +48,31 @@ class CaseInsensitiveListFilter(BaseInFilter, CharFilter):
|
||||||
class ProductFilter(FilterSet):
|
class ProductFilter(FilterSet):
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
||||||
name = CharFilter(field_name="name", lookup_expr="icontains", label=_("Name"))
|
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)")
|
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"))
|
tags = CaseInsensitiveListFilter(field_name="tags__tag_name", label=_("Tags"))
|
||||||
min_price = NumberFilter(field_name="stocks__price", lookup_expr="gte", label=_("Min Price"))
|
min_price = NumberFilter(
|
||||||
max_price = NumberFilter(field_name="stocks__price", lookup_expr="lte", label=_("Max Price"))
|
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"))
|
is_active = BooleanFilter(field_name="is_active", label=_("Is Active"))
|
||||||
brand = CharFilter(field_name="brand__name", lookup_expr="iexact", label=_("Brand"))
|
brand = CharFilter(field_name="brand__name", lookup_expr="iexact", label=_("Brand"))
|
||||||
attributes = CharFilter(method="filter_attributes", label=_("Attributes"))
|
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"))
|
slug = CharFilter(field_name="slug", lookup_expr="exact", label=_("Slug"))
|
||||||
is_digital = BooleanFilter(field_name="is_digital", label=_("Is Digital"))
|
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(
|
order_by = OrderingFilter(
|
||||||
fields=(
|
fields=(
|
||||||
|
|
@ -111,13 +123,16 @@ class ProductFilter(FilterSet):
|
||||||
)
|
)
|
||||||
self.queryset = self.queryset.annotate(
|
self.queryset = self.queryset.annotate(
|
||||||
rating=Coalesce(
|
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):
|
def filter_include_flag(self, queryset, **_kwargs):
|
||||||
if not self.data.get("category_uuid"):
|
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
|
return queryset
|
||||||
|
|
||||||
def filter_attributes(self, queryset, _name, value):
|
def filter_attributes(self, queryset, _name, value):
|
||||||
|
|
@ -240,7 +255,8 @@ class ProductFilter(FilterSet):
|
||||||
)
|
)
|
||||||
qs = qs.annotate(
|
qs = qs.annotate(
|
||||||
rating=Coalesce(
|
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()
|
return qs.distinct()
|
||||||
|
|
@ -252,14 +268,26 @@ class OrderFilter(FilterSet):
|
||||||
label=_("Search (ID, product name or part number)"),
|
label=_("Search (ID, product name or part number)"),
|
||||||
)
|
)
|
||||||
|
|
||||||
min_buy_time = DateTimeFilter(field_name="buy_time", lookup_expr="gte", label=_("Bought after (inclusive)"))
|
min_buy_time = DateTimeFilter(
|
||||||
max_buy_time = DateTimeFilter(field_name="buy_time", lookup_expr="lte", label=_("Bought before (inclusive)"))
|
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")
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||||
user_email = CharFilter(field_name="user__email", lookup_expr="iexact", label=_("User email"))
|
user_email = CharFilter(
|
||||||
user = UUIDFilter(field_name="user__uuid", lookup_expr="exact", label=_("User UUID"))
|
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"))
|
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(
|
order_by = OrderingFilter(
|
||||||
fields=(
|
fields=(
|
||||||
|
|
@ -299,11 +327,20 @@ class OrderFilter(FilterSet):
|
||||||
|
|
||||||
class WishlistFilter(FilterSet):
|
class WishlistFilter(FilterSet):
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||||
user_email = CharFilter(field_name="user__email", lookup_expr="iexact", label=_("User email"))
|
user_email = CharFilter(
|
||||||
user = UUIDFilter(field_name="user__uuid", lookup_expr="exact", label=_("User UUID"))
|
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(
|
order_by = OrderingFilter(
|
||||||
fields=(("uuid", "uuid"), ("created", "created"), ("modified", "modified"), ("?", "random"))
|
fields=(
|
||||||
|
("uuid", "uuid"),
|
||||||
|
("created", "created"),
|
||||||
|
("modified", "modified"),
|
||||||
|
("?", "random"),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -317,7 +354,9 @@ class CategoryFilter(FilterSet):
|
||||||
parent_uuid = CharFilter(method="filter_parent_uuid", label=_("Parent"))
|
parent_uuid = CharFilter(method="filter_parent_uuid", label=_("Parent"))
|
||||||
slug = CharFilter(field_name="slug", lookup_expr="exact", label=_("Slug"))
|
slug = CharFilter(field_name="slug", lookup_expr="exact", label=_("Slug"))
|
||||||
whole = BooleanFilter(
|
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"))
|
tags = CaseInsensitiveListFilter(field_name="tags__tag_name", label=_("Tags"))
|
||||||
level = NumberFilter(field_name="level", lookup_expr="exact", label=_("Level"))
|
level = NumberFilter(field_name="level", lookup_expr="exact", label=_("Level"))
|
||||||
|
|
@ -332,7 +371,16 @@ class CategoryFilter(FilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Category
|
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):
|
def filter_whole_categories(self, queryset, _name, value):
|
||||||
has_own_products = Exists(Product.objects.filter(category=OuterRef("pk")))
|
has_own_products = Exists(Product.objects.filter(category=OuterRef("pk")))
|
||||||
|
|
@ -364,7 +412,9 @@ class CategoryFilter(FilterSet):
|
||||||
class BrandFilter(FilterSet):
|
class BrandFilter(FilterSet):
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact")
|
||||||
name = CharFilter(field_name="name", lookup_expr="icontains", label=_("Name"))
|
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(
|
order_by = OrderingFilter(
|
||||||
fields=(
|
fields=(
|
||||||
|
|
@ -381,8 +431,16 @@ class BrandFilter(FilterSet):
|
||||||
|
|
||||||
class FeedbackFilter(FilterSet):
|
class FeedbackFilter(FilterSet):
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
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"))
|
product_uuid = UUIDFilter(
|
||||||
user_uuid = UUIDFilter(field_name="order_product__order__user__uuid", lookup_expr="exact", label=_("User UUID"))
|
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(
|
order_by = OrderingFilter(
|
||||||
fields=(
|
fields=(
|
||||||
|
|
@ -402,8 +460,12 @@ class FeedbackFilter(FilterSet):
|
||||||
|
|
||||||
class AddressFilter(FilterSet):
|
class AddressFilter(FilterSet):
|
||||||
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
uuid = UUIDFilter(field_name="uuid", lookup_expr="exact", label=_("UUID"))
|
||||||
user_uuid = UUIDFilter(field_name="user__uuid", lookup_expr="exact", label=_("User UUID"))
|
user_uuid = UUIDFilter(
|
||||||
user_email = CharFilter(field_name="user__email", lookup_expr="iexact", label=_("User email"))
|
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(
|
order_by = OrderingFilter(
|
||||||
fields=(
|
fields=(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue