views:

51

answers:

3

The model has an IntegerField with null=True, blank=True, so it allows the field to have a value of None. When the column is sorted, the Nones are always treated as the lowest values. Is it possible to make Django treat them as the highest values? So when sorted in descending order, instead of:

100 43 7 None

It would go:

None 100 43 7

I realize I could assign an extremely high number instead of None, but for neatness' sake, I was wondering if there were any other options.

Thanks!

A: 

It's not Django that determines the sort order, but the database. And databases have their own rules about how to sort NULLs.

One (rather complicated) possibility would be to implement a custom field that uses a custom database type to sort in the correct order. The details of how you would do this are likely to depend on your database.

Daniel Roseman
+1  A: 

Daniel is correct in that the database determines the sort order, and different databases treat the ordering of NULLs differently. However, there are ways to get the DB to give you the order you want.

PostgreSQL is nice enough to actually allow you to append "NULLS FIRST" or "NULLS LAST" to your query (ref).

SELECT * FROM table_name ORDER BY int_field DESC NULLS FIRST;

For MySQL and SQLite, there's an alternative (which will also work in PostgreSQL), as described here. Essentially, if you want nulls last, you would do:

SELECT *, int_field IS NULL AS is_null FROM table_name ORDER BY is_null DESC, int_field DESC;

However, getting Django to execute these queries is a different story alltogether. In Django 1.2, model managers now have a raw() method, documented here, which returns a RawQuerySet, which is like a QuerySet, but can't be stacked (e.g. you can't add a filter() call in there). Of course, instead of stacking, you can just add your lookup parameters to the SQL. Whether or not this functionality is useful to you depends on what you're trying to accomplish. If you simply want to fetch your models in that order then pass the queryset to a view or something, you can do:

YourModel.objects.raw('SELECT *, int_field IS NULL AS is_null FROM table_name ORDER BY is_null DESC, int_field DESC')

If however you want this to be the default ordering for use in the admin and such, you'll need a different approach, perhaps via overriding the manager.

Aram Dulyan
A: 

Since I'm using Django 1.1 and couldn't use raw(), the simplest way turned out to be to create a "int_sort" field, and populate it with the value of the IntegerField, unless it encountered a None, in which case it would take the value of sys.maxint.

Then, in admin.py, I set the admin_order_field to be the "int_sort" field.

zbar