如何在Django中按过期日期排序Ticket模型并将无日期项置于末尾?
问题
我有一个Ticket模型,包含sum字段。需求是按最近过期日期优先使用票券,但直接按date_expire字段排序时,date_expire=None(代表无时间限制)的票券会排在最前面——而这类无期限票券应该放在所有有时间限制的票券之后。
我的原代码:
ticket = Tickets.objects.filter( sum__gte=0, date_expire__gte=timezone.now(), user_id=user.id, burned=False ).order_by( 'date_expire' ).first()
我考虑过用Python内置的sorted函数结合lambda表达式排序,但觉得通过ORM直接实现会更高效、更符合数据库层面的优化原则。
解决方案
后来我摸索出了一个可行的实现方案,代码如下:
ticket = Tickets.objects.filter( sum__gte=0, date_expire__gte=timezone.now(), user_id=user.id, burned=False ).annotate( has_date=Func(F('date_expire'), Value(None), function='IFNULL') ).order_by( '-has_date', 'date_expire' ).first()
实现逻辑
通过QuerySet的annotate方法生成一个临时字段has_date,该字段调用SQL的IFNULL函数:当date_expire不为NULL时返回字段本身的值,为NULL时返回NULL。
对应的SQL生成的字段如下:
IFNULL("tickets"."date_expire", NULL) AS "has_date"
排序时先按-has_date倒序,这样有过期时间的票券会被优先排在前面,无期限的票券(date_expire为NULL)则会被排在所有有时间限制的票券之后;接着再按date_expire正序,确保有期限的票券中最近过期的会被优先选中。
这个方案能够满足我的需求,不过可能存在更简洁或更高效的实现方式。
内容的提问来源于stack exchange,提问作者NelttjeN
相关产品推荐
相关产品推荐

