【问题标题】:How to order a combined queryset by annotated field?如何按带注释的字段订购组合查询集?
【发布时间】:2022-12-06 23:51:05
【问题描述】:

我们对象的权重由 2 个字段组成。一个字段是重量单位(千克、吨和磅),另一个字段是重量(数字)。我尝试制作一个查询集,将所有权重注释到一个通用单位字段中。问题是,一旦我 order_by 那个带注释的(单位)字段,它仍然按最大数量而不是最大重量排序。

例如 100kg 小于 50t,但订货系统只是按最大的数排序。

这是 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 filter django-queryset annotate


    【解决方案1】:

    您可以使用 conditional expression [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

    【讨论】:

      猜你喜欢
      • 2013-03-25
      • 2021-09-06
      • 2020-08-30
      • 2021-01-27
      • 2013-08-11
      • 2019-08-03
      • 1970-01-01
      • 2019-12-19
      • 2020-05-09
      相关资源
      最近更新 更多