Как упорядочить объединенный набор запросов по аннотированному полю?

Вес для наших объектов состоит из 2 полей. Одно поле - единица измерения веса (килограмм, тонна и фунт), а другое поле - вес (число). Я попробовал сделать кверисет, который аннотирует все веса в одно универсальное поле единицы измерения. Проблема в том, что когда я упорядочиваю_по этому аннотированному полю (единица измерения), оно по-прежнему упорядочивает по наибольшему числу, а не по наибольшему весу

Например, 100 кг меньше 50 т, но система заказа просто сортирует по наибольшему числу.

Это код внутри filters.py:

`

class AircraftFilter(FilterSet):
    tail_number = CharFilter(field_name="tail_number", lookup_expr="startswith")
    by_weight = CharFilter(method="filter_by_weight")

    class Meta:
        model = Aircraft
        fields = ("tail_number", "by_weight")

    def filter_by_weight(self, qs: QuerySet, value, *args, **kwargs):
        if value != None:
            qs = (
                qs.filter(max_takeoff_weight_unit=2).annotate(
                    mtw_lb=F("max_takeoff_weight") * 2200
                )
                | qs.filter(max_takeoff_weight_unit=1).annotate(
                    mtw_lb=F("max_takeoff_weight") * 2.2
                )
                | qs.filter(max_takeoff_weight_unit=3).annotate(
                    mtw_lb=F("max_takeoff_weight")
                )
            )
            qs = qs.order_by("mtw_lb")
        return qs

`

Запрос:

`qs = (Aircraft.objects.all().filter(max_takeoff_weight_unit=2).annotate(mtw_lb=F("max_takeoff_weight")*2200) | Aircraft.objects.all().filter(max_takeoff_weight_unit=1).annotate(mtw_lb=F("max_takeoff_weight") * 2.2) | Aircraft.objects.all().filter(max_takeoff_weight_unit=3).annotate(mtw_lb=F("max_takeoff_weight"))).order_by("mtw_lb")`

и вывод:

`<IsActiveModelQuerySet [ID: 5 | weight: 0.05 - (t) , ID: 4 | weight: 0.20 - (t) , ID: 8 | weight: 2.00 - (t) , ID: 7 | weight: 50.00 - (lbs) , ID: 6 | weight: 100.00 - (kg) ]>`

Вы можете фильтровать с помощью условного выражения [Django-doc], так:

from django.db.models import Case, F, When


class AircraftFilter(FilterSet):
    tail_number = CharFilter(field_name='tail_number', lookup_expr='startswith')
    by_weight = CharFilter(method='filter_by_weight')

    class Meta:
        model = Aircraft
        fields = ('tail_number', 'by_weight')

    def filter_by_weight(self, qs: QuerySet, value, *args, **kwargs):
        if value is not None:
            qs = (
                qs.annotate(
                    mtw_lb=Case(
                        When(
                            max_takeoff_weight_unit=2,
                            then=F('max_takeoff_weight') * 2200,
                        ),
                        When(
                            max_takeoff_weight_unit=1,
                            then=F('max_takeoff_weight') * 2.2,
                        ),
                        When(
                            max_takeoff_weight_unit=3,
                            then=F('max_takeoff_weight'),
                        ),
                    )
                )
            ).order_by('mtw_lb')
        return qs

или проще:

from django.db.models import Case, F, When


class AircraftFilter(FilterSet):
    tail_number = CharFilter(field_name='tail_number', lookup_expr='startswith')
    by_weight = CharFilter(method='filter_by_weight')

    class Meta:
        model = Aircraft
        fields = ('tail_number', 'by_weight')

    def filter_by_weight(self, qs: QuerySet, value, *args, **kwargs):
        if value is not None:
            qs = (
                qs.annotate(
                    mtw_lb=F('max_takeoff_weight')
                    * Case(
                        When(
                            max_takeoff_weight_unit=2,
                            then=Value(2200),
                        ),
                        When(
                            max_takeoff_weight_unit=1,
                            then=Value(2.2),
                        ),
                        When(
                            max_takeoff_weight_unit=3,
                            then=Value(1),
                        ),
                    )
                )
            ).order_by('mtw_lb')
        return qs
Вернуться на верх