Django ORM使用Case和When条件表达式
问题
有这么一个需求,需要根据订单的创建时间和更新时间排序,要按照最后的操作时间进行排序。
比如,在26分创建了一个订单a,在27分创建了一个订单b,然后在28分修改订单a,又在29分创建了订单c,那么此时订单的排序结果,应该是c,a,b。
表中数据(时间是示例,实际是datetime.datetime类型):
ID | 订单号 | 创建时间 | 更新时间 |
---|---|---|---|
1 | a | 26 | 28 |
2 | b | 27 | |
3 | c | 29 |
方案
一开始的想法是根据更新时间排序,然后更新时间为空的,按照创建时间排序。但是这种方式对于没有更新时间的数据,筛选出来会出现排序混乱的问题。
后来想到可以将两个字段合成一个字段,这样就可以对这个字段排序了,但是也有问题,合成一个字段,会出现数据重复,而且也不好筛选和过滤。
在网上搜了搜,看到可以使用SQL的条件表达式,case,when,then。
实现
SQL使用条件表达式,可以判断update_time是否为空,如果有值,则使用自己的值,如果没有值则使用create_time,并且可以对结果使用别名,然后根据这个别名来进行排序。这样排序的时候就会同时根据更新时间和创建时间来排序。
代码示例
完整代码示例:
from django.db.models import Case, DateTimeField, F, When
# 查询所有的数据,只要queryset是Django查询集即可
queryset = Order.objects.all()
#
queryset.annotate(
op_time=Case(
When(update_time=F("update_time"), then=F("update_time"),),
default=F("create_time"),
output_field=DateTimeField(),
),
).order_by("-op_time")
完整的SQL示例:
SELECT
id,
create_time,
update_time,
(
CASE update_time
WHEN update_time THEN
update_time
ELSE
create_time
END) AS t
FROM
courtesy_car_order
ORDER BY
t DESC