58👍
You can use the annotate() from django agrregation to do the trick:
items = Item.objects.all().annotate(null_position=Count('position')).order_by('-null_position', 'position')
21👍
As of Django 1.8 you can use Coalesce()
to convert NULL
to 0
.
Sample:
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')
- [Django]-How to set a Django model field's default value to a function call / callable (e.g., a date relative to the time of model object creation)
- [Django]-Do properties work on Django model fields?
- [Django]-Django.core.servers.basehttp.FileWrapper disappears in Django 1.9
14👍
It’s a shame there are a lot of questions like this on SO that are not marked as duplicate. See (for example) this answer for the native solution for Django 1.11 and newer. Here is a short excerpt:
Added the nulls_first and nulls_last parameters to Expression.asc() and desc() to control the ordering of null values.
Example usage (from comment to that answer):
from django.db.models import F
MyModel.objects.all().order_by(F('price').desc(nulls_last=True))
Credit goes to the original answer author and commenter.
- [Django]-Django : Serving static files through nginx
- [Django]-How do I unit test django urls?
- [Django]-Django – present current date and time in template
9👍
Using extra() as Ignacio said optimizes a lot the end query. In my aplication I’ve saved more than 500ms (that’s a lot for a query) in database processing using extra() instead of annotate()
Here is how it would look like in your case:
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} should be something like {Item’s app}_item following django’s default tables name.
- [Django]-Django DoesNotExist
- [Django]-How do I return JSON without using a template in Django?
- [Django]-Manage.py runserver
3👍
I found that the syntax in Pablo’s answer needed to be updated to the following on my 1.7.1 install:
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')
- [Django]-How do I use Django templates without the rest of Django?
- [Django]-How to redirect with post data (Django)
- [Django]-Django What is reverse relationship?
1👍
QuerySet.extra()
can be used to inject expressions into the query and order by them.
- [Django]-Proper way to handle multiple forms on one page in Django
- [Django]-RuntimeError: Model class django.contrib.sites.models.Site doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS
- [Django]-Uwsgi installation error in windows 7