Django:按位置sorting忽略NULL
我有一个django querysetsorting问题。
我的模型包含一个名为position
(一个PositiveSmallIntegerField )的字段,我想用它来sorting查询结果。
我使用order_by('position')
,这很好。
问题 :我的position
字段为空( null=True, blank=True
),因为我不想为每个50000个实例指定一个位置:(
当一些实例有一个NULL“位置”时, order_by
将它们返回到列表顶部:我希望它们在最后…
在RAW SQL中,我曾经写过“ IF(position IS NULL or position='', 1, 0)
”(请参阅http://www.shawnolson.net/a/730/mysql-sort-order-with -null.html ):是否有可能得到相同的结果使用Django,而不写入原始的SQL?
非常感谢 !
你可以使用django agrregation中的annotate()来实现这个技巧:
items = Item.objects.all().annotate(null_position=Count('position')).order_by('-null_position', 'position')
从Django 1.8开始,您可以使用Coalesce()
将NULL
转换为0
。
样品:
import datetime from django.db.models.functions import Coalesce, Value from app import models # Coalesce works by taking the first non-null value. So we give it # a date far before any non-null values of last_active. Then it will # naturally sort behind instances of Box with a non-null last_active value. the_past = datetime.datetime.now() - datetime.timedelta(days=10*365) boxes = models.Box.objects.all().annotate( new_last_active=Coalesce( 'last_active', Value(the_past) ) ).order_by('-new_last_active')
使用extra()作为Ignacio说优化了很多结束查询。 在我的应用程序中,我使用extra()而不是annotate()在数据库处理中节省了超过500毫秒的时间(这对于查询来说很多)
以下是你的情况:
items = Item.objects.all().extra( 'select': { 'null_position': 'CASE WHEN {tablename}.position IS NULL THEN 0 ELSE 1 END' } ).order_by('-null_position', 'position')
{tablename}应该像django的默认表名一样,是{Item的app} _item 。
我发现在我的1.7.1安装中,Pablo答案中的语法需要更新为以下内容:
items = Item.objects.all().extra(select={'null_position': 'CASE WHEN {name of Item's table}.position IS NULL THEN 0 ELSE 1 END'}).order_by('-null_position', 'position')
QuerySet.extra()
可用于将expression式注入查询并按顺序排列。