Features: 1) Add Prefetch import in filters.py; 2) Introduce filter_order_by method with custom ordering logic for Category model.

Fixes: 1) Replace `OrderingFilter` with `CharFilter` for `order_by` field in `CategoryFilter`.

Extra: 1) Remove unused ordering configuration from `order_by` field; 2) Refactor ordering logic with prefetch-related optimization for children categories.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-09-05 19:20:48 +03:00
parent eecb4c9ec4
commit d811d1e5fe

View file

@ -15,6 +15,7 @@ from django.db.models import (
Value, Value,
When, When,
Max, Max,
Prefetch,
) )
from django.db.models.functions import Coalesce from django.db.models.functions import Coalesce
from django.utils.http import urlsafe_base64_decode from django.utils.http import urlsafe_base64_decode
@ -382,14 +383,7 @@ class CategoryFilter(FilterSet):
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"))
order_by = OrderingFilter( order_by = CharFilter(method="filter_order_by")
fields=(
("priority", "priority"),
("uuid", "uuid"),
("name", "name"),
("?", "random"),
)
)
class Meta: class Meta:
model = Category model = Category
@ -404,6 +398,35 @@ class CategoryFilter(FilterSet):
"whole", "whole",
] ]
def filter_order_by(self, queryset, _name, value):
if not value:
return queryset
desc = value.startswith("-")
key = value.lstrip("-")
mapping = {
"priority": "priority",
"uuid": "uuid",
"name": "name",
"?": "random",
}
field = mapping.get(key)
if field is None:
return queryset
if field == "?":
parent_order = "?"
child_order = "?"
else:
parent_order = f"-{field}" if desc else field
child_order = parent_order
qs = queryset.order_by(parent_order)
children_qs = Category.objects.all().order_by(child_order)
return qs.prefetch_related(Prefetch("children", queryset=children_qs))
def filter_name(self, queryset, _name, value): def filter_name(self, queryset, _name, value):
search_results = process_query(query=value, request=self.request)["categories"] search_results = process_query(query=value, request=self.request)["categories"]
uuids = [res["uuid"] for res in search_results if res.get("uuid")] uuids = [res["uuid"] for res in search_results if res.get("uuid")]