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.
精彩评论