diff --git a/core/filters.py b/core/filters.py index aa6c138c..f0cebd1c 100644 --- a/core/filters.py +++ b/core/filters.py @@ -15,6 +15,7 @@ from django.db.models import ( Value, When, Max, + Prefetch, ) from django.db.models.functions import Coalesce from django.utils.http import urlsafe_base64_decode @@ -382,14 +383,7 @@ class CategoryFilter(FilterSet): tags = CaseInsensitiveListFilter(field_name="tags__tag_name", label=_("Tags")) level = NumberFilter(field_name="level", lookup_expr="exact", label=_("Level")) - order_by = OrderingFilter( - fields=( - ("priority", "priority"), - ("uuid", "uuid"), - ("name", "name"), - ("?", "random"), - ) - ) + order_by = CharFilter(method="filter_order_by") class Meta: model = Category @@ -404,6 +398,35 @@ class CategoryFilter(FilterSet): "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): search_results = process_query(query=value, request=self.request)["categories"] uuids = [res["uuid"] for res in search_results if res.get("uuid")]