Features: 1) Add personal_order_only ordering option; 2) Annotate queryset with personal_order_only calculated field; 3) Support custom ordering for price and personal_order_only.

Fixes: 1) Correct `rating` ordering logic to use cleaned field names without signs.

Extra: 1) Add missing import for `BooleanField`; 2) Refactor ordering parameter processing for clarity and efficiency.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-09-16 15:04:59 +03:00
parent 143cd6804b
commit 91b043ac4f

View file

@ -16,6 +16,7 @@ from django.db.models import (
When,
Max,
Prefetch,
BooleanField,
)
from django.db.models.functions import Coalesce
from django.utils.http import urlsafe_base64_decode
@ -92,6 +93,7 @@ class ProductFilter(FilterSet):
("price_order", "price"),
("sku", "sku"),
("?", "random"),
("personal_order_only", "personal_order_only"),
),
initial="uuid",
)
@ -279,8 +281,8 @@ class ProductFilter(FilterSet):
ordering_param = self.data.get("order_by", "")
if ordering_param:
order_fields = [field.strip() for field in ordering_param.split(",")]
if any(field.lstrip("-") == "rating" for field in order_fields):
order_fields_no_sign = [field.strip("-") for field in ordering_param.split(",")]
if "rating" in order_fields_no_sign:
feedback_qs = (
Feedback.objects.filter(order_product__product_id=OuterRef("pk"))
.values("order_product__product_id")
@ -293,6 +295,43 @@ class ProductFilter(FilterSet):
Value(0, output_field=FloatField()),
)
)
if ordering_param and any(f.lstrip("-") == "price" for f in ordering_param.split(",")):
qs = qs.annotate(
price_order=Coalesce(
Max("stocks__price"),
Value(0.0),
output_field=FloatField(),
)
)
qs = qs.annotate(
personal_order_only=Case(
When(has_stock=Value(0), has_price=Value(1), then=Value(True)),
default=Value(False),
output_field=BooleanField(),
)
)
requested = [part.strip() for part in ordering_param.split(",") if part.strip()] if ordering_param else []
mapped_requested = []
for part in requested:
desc = part.startswith("-")
key = part.lstrip("-")
if key == "price":
key = "price_order"
if key == "random":
key = "?"
mapped_requested.append(key)
continue
mapped_requested.append(f"-{key}" if desc else key)
has_personal_in_request = any(p.lstrip("-") == "personal_order_only" for p in mapped_requested)
final_ordering = (["personal_order_only"] if not has_personal_in_request else []) + mapped_requested
if final_ordering:
qs = qs.order_by(*final_ordering)
return qs.distinct()