Django:按位置排序忽略NULL

时间:2011-03-08 16:20:29

标签: django sql-order-by nullable

我对django queryset排序有疑问。

我的模型包含一个名为position的字段( PositiveSmallIntegerField ),我想用它来订购查询结果。

我使用order_by('position'),效果很好。

问题:我的position字段可以为空(null=True, blank=True),因为我不想为我的模型的每50000个实例指定一个位置:(

当某些实例具有NULL“position”时,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?

非常感谢!

6 个答案:

答案 0 :(得分:57)

您可以使用django agrregation中的annotate()来完成这一操作:

items = Item.objects.all().annotate(null_position=Count('position')).order_by('-null_position', 'position')

答案 1 :(得分:19)

从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')

答案 2 :(得分:9)

使用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's app} _item

答案 3 :(得分:5)

很遗憾在SO上有很多这样的问题都没有标记为重复。有关Django 1.11及更新版本的本机解决方案,请参阅(例如)this answer。这是一个简短的摘录:

  

在Expression.asc()和desc()中添加了nulls_first和nulls_last参数,以控制空值的排序。

示例用法(从评论到答案):

from django.db.models import F 
MyModel.objects.all().order_by(F('price').desc(nulls_last=True))

归功于最初的答案作者和评论者。

答案 4 :(得分:3)

我发现Pablo的答案中的语法需要在我的1.7.1安装中更新到以下内容:

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')

答案 5 :(得分:1)

QuerySet.extra()可用于将表达式注入查询并按顺序排序。