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式注入查询并按顺序排列。