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