Как упорядочить объединенный набор запросов по аннотированному полю?
Вес для наших объектов состоит из 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