开发者

Django ORM: Ordering w/ aggregate functions — None special treatment

开发者 https://www.devze.com 2022-12-25 19:19 出处:网络
I\'m doing this query: SomeObject.objects.annotate(something=Avg(\'something\')).order_by(something).all()

I'm doing this query:

SomeObject.objects.annotate(something=Avg('something')).order_by(something).all()

I normally have an aggregate field in my model that I use with Django signals to keep in sync, however in this case perfomance isn't an issue so I thought I'd keep it simple and just use subqueries.

This approach, however, presented an unexpected issue. It all works great if aggregate function results are like:

[5.0, 4.0, 6.0 … (etc, just numbers)]

However if you mix in some None's than it is ordered like this:

[None, 5.0, 4.0 …]

The issue is that None has higher value than any number, while it should have value at most a value of 0.

I'm using PostgreSQL and haven't tested w/ other DBs. I haven't actually checked what query is generated etc.

I worked it around by just sorting in memory:

sorted(…, key=lambda _:_.avg_开发者_如何转开发rating if _.avg_rating is not None else 0) 

So I'm just curious if there is a way to do it with just the Django ORM? Perhaps .where? Or something else?


How about just adding a has_something=1,0 via extra() and then order on both has_something and 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() 

Not 100% ORM in the strictest sense but it does push the sorting back into the DB.

0

精彩评论

暂无评论...
验证码 换一张
取 消