我需要根据布尔字段对查询集的两个部分进行不同的排序。 - 具有bool_val == True的行应首先出现,并按date_a排序,以升序排序。 - 具有bool_val == False的行应该排在第二位,并按date_b排序,降序。
我最接近的是
MyModel.objects.all().annotate(
sort_order=Case(
When(bool_val=True, then=('date_a')),
default='date_b')
).order_by('-bool_val', 'sort_order')
但是,它们按照相同的顺序对它们进行排序。如果我需要排序的值是数字,那么我会在我的注释中将一个设置乘以-1,但是它们是日期值,因此不会起作用。
我也考虑过创建两个单独的查询集并将它们组合起来,但是union()在1.11之前是不可用的,我必须支持1.10,以及其他组合查询集的方法发现要么不保留订单,要么不会导致查询集(或两者)。 (我不清楚union()是否保留了秩序,但它没有实际意义,所以我也没有深入研究它。)这必须是一个django QuerySet对象at结束。
答案 0 :(得分:2)
这就是最终的工作:
MyModel.objects.annotate(
sort_order_true=Case(
When(bool_val=True, then=('date_a')),
default=None
),
sort_order_false=Case(
When(bool_val=False, then=('date_b')),
default=None
)
).order_by(
'sort_order_true',
'-sort_order_false',
)
答案 1 :(得分:0)
您应该能够使用Func
表达式将日期时间转换为时间戳,以便您可以否定它们。
对于MySQL,这是UNIX_TIMESTAMP
函数
MyModel.objects.annotate(
sort_order=Case(
When(bool_val=True, then=Func(F('date_a'), function='UNIX_TIMESTAMP')),
When(bool_val=False, then=Value(0) - Func(F('date_b'), function='UNIX_TIMESTAMP')),
)
).order_by('-bool_val', 'sort_order')
对于PostgreSQL,这是EXTRACT(EPOCH FROM TIMESTAMP WITH TIME ZONE '<datetime>')
MyModel.objects.annotate(
sort_order=Case(
When(bool_val=True, then=Func(F('date_a'), function='UNIX_TIMESTAMP')),
When(bool_val=False, then=Value(0) - Func('EPOCH FROM TIMESTAMP WITH TIME ZONE', F('date_b'), function='EXTRACT', arg_joiner=' ')),
)
).order_by('-bool_val', 'sort_order')
有点麻烦......而且可能很慢。我没有测试过这个