Django ORM:使用聚合函数排序 — 无特殊处理
我正在执行这个查询:
SomeObject.objects.annotate(something=Avg('something')).order_by(something).all()
我通常在我的模型中有一个聚合字段,用于配合Django信号保持同步,不过在这种情况下,性能不是问题,所以我想简单点,直接使用子查询。
然而,这种方法出现了一个意想不到的问题。只要聚合函数的结果是这样的:
[5.0, 4.0, 6.0 … (etc, just numbers)]
一切都运行得很好。但是如果结果中混入了一些 None
,那么排序就会变成这样:
[None, 5.0, 4.0 …]
问题在于,None
的值比任何数字都要高,而它的值应该最多是0。
我使用的是PostgreSQL,没测试过其他数据库。我实际上也没有检查生成了什么查询等等。
我通过在内存中排序来解决了这个问题:
sorted(…, key=lambda _:_.avg_rating if _.avg_rating is not None else 0)
所以我只是好奇,是否有办法仅通过Django的ORM来做到这一点?也许可以用 .where
?或者其他什么方法?
1 个回答
2
你可以试试通过extra()添加一个has_something=1,0,然后在has_something和something这两个字段上进行排序。
with_avg = SomeObject.objects.annotate(avg=Avg('something'))
with_avg_and_has = with_avg.extra(select={'has_something': 'something is NULL'})
sorted_result = with_avg_and_has.order_by('-has_something', '-avg').all()
这不是严格意义上的ORM(对象关系映射),但确实把排序的工作放回了数据库里。