I have a model of work orders, with a field for when the work order is required by. To get a list of work orders, with those that are required early, I do this:
wo = Work_Order.objects.order_by('dateWORequired')
This works nicely, but ONLY if there is actually a value in that field. If there is no required date, then the value is None
. Then, the list of work orders has all the None
's at the top, and then the remaining work orders in proper order.
How can I get the None
's at the bottom?
You might need a - before the date_is_null in the order_by portion, but that's how you can control the behavior.
I endeavoured to get this working with pure Django, without dropping into SQL.
The F() expression function can be used with order_by, so I tried to concoct a way of creating an expression which sets all numbers to the same value, but which sets all NULLs to another specific value.
MySQL will order NULLs before 0s in ascending order, and vice versa in descending order.
So this works:
You can then pass any other fields to the same order_by call, before or after that expression.
I've tried it with dates and the same happens. e.g.:
Evaluates to 0.
This was not available when the question was asked, but since Django 1.8 I think this is the best solution:
Coalesce
selects the first non-null value, so you create a valuedate_null
to order by which is just dateWORequired but withnull
replaced by a date long ago.Requirements: Python 3.4, Django 10.2, PostgreSQL 9.5.4
Variant 1
Solution:
Usage (None always latest):
Notes
Variant 2
Solution:
Usage:
Results (None always latest):
Notes:
Based on the Django: Adding "NULLS LAST" to query and the Django`s source code
Global on all fields of a model (it is advantage and disadvantage simultaneously)
No a unnecessary field
A drawback - tested only on the PostgreSQL
Django 1.11 added this as a native feature. It's a little convoluted. It is documented.
Ordered with only one field, ascending:
Ordered using two fields, both descending: