From d811d1e5fea331ea83842fa397215298155ebd80 Mon Sep 17 00:00:00 2001 From: Egor fureunoir Gorbunov Date: Fri, 5 Sep 2025 19:20:48 +0300 Subject: [PATCH] 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. --- core/filters.py | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) 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")]