Custom sort algorithm for a field in newforms-admin?

196 views
Skip to first unread message

Paul Winkler

unread,
Jul 31, 2008, 7:07:41 PM7/31/08
to Django users
Hi,

I have a django admin app that I wrote using newforms-admin. I have
the same problem described by whoever created this bug:
http://code.djangoproject.com/ticket/6604
... and I have not turned up an answer yet by googling.

In summary, when a user clicks on a column header on my model's
change_list page, the ORDER BY in the db query is doing an
alphabetical sort, but we need a numeric sort (like `sort -n` on a
unix system).

The algorithm would be easy if I only knew how to wire it up to my
admin view.

(Aside: I don't expect performance to ever be an issue; the table in
question currently has ~100 rows and it is unlikely to ever get beyond
10k rows, to say nothing of 100k where I suspect a python sort would
still be just fast enough for my users.)

I've read everything about sorting and ordering I can find in Django
docs, but if there's anything that can help me, I missed it...

thanks!


Martin Diers

unread,
Jul 31, 2008, 7:20:46 PM7/31/08
to django...@googlegroups.com
The reason you have not found the algorithm in Django is because it's
not in Django. The ordering attribute in a Model or ModelAdmin class
simply sets the ORDER BY clause in SQL.

Therefore, you would have to go about this in some other way. One
option which I have used is to add a new column to your Model, and pre-
populate it with a zero-padded string representation of your number
column in your Model's overriden save() method. It's extra data, but
the only easy way to implement this.

In an SQL query, this would be pretty simple to implement, using
to_char() (for postgres) or lpad(cast()) for MySQL, to create an
"alias" column. If there is a way to do this in Django, I'd like to
know about it, because it would be pretty darn useful - although
totally DB specific. I'm thinking a read-only column based upon a SQL
fragment, which could then be mapped to a Django model attribute, and
referenced in an order_by() clause.

Paul Winkler

unread,
Jul 31, 2008, 8:05:13 PM7/31/08
to Django users
Thanks, storing extra data sounds like a viable approach.

But how would I get the change_list view to use one field for display
and another field for sorting that column?
I'm still a django novice so I'd greatly appreciate any hints on where
to look.

- PW

Martin Diers

unread,
Jul 31, 2008, 8:57:43 PM7/31/08
to django...@googlegroups.com
You can set the initial sort in the Meta class, ordering attribute, of your ModelAdmin for that model. The field you set does not have to be one of the fields that you have chosen to display in the list view. It can be any field. It's just the default sort.

Keep in mind, however, that once a user clicks a sortable column heading, there is no way to get the default sort back, without leaving and going back into the change list.

There is a way to swap in a hidden sort on your number column, but it's tricky. It is possible to override the change list template for the Admin, just for a specific model. Study the code and templates for the change list in contrib.admin and learn how it works. Otherwise the next part will make no sense.

You will need to create your own version of the result_list tag. Then you can override the change_list.html template and call your new tag, instead of result_list. Your new tag can just be an inclusion tag which brings in a custom version of the change_list_results.html template. In the top of that template, there is code which sets the URL for the href of the sortable column headings. From there you can add a test which swaps out the URL to invoke the sorting of your hidden column.

This is a pain, but it will work. The change list in the new admin could use a lot of work to allow easier customization. However, what we have now is a huge step forward from where we were with the old admin.

 See ticket http://code.djangoproject.com/ticket/7943 for the docs on how to 
override admin templates.

Norman Harman

unread,
Aug 1, 2008, 10:14:36 AM8/1/08
to django...@googlegroups.com
Paul Winkler wrote:
> Thanks, storing extra data sounds like a viable approach.
>
> But how would I get the change_list view to use one field for display
> and another field for sorting that column?

In your model add method like this:

def _get_foo(self):
return self.the_display_column
_get_foo.short_description = "Whatever"
_get_foo.admin_order_field = "the_sort_column"

Django looks for those special method attributes. More info here
http://www.djangoproject.com/documentation/admin/


And in your ModelAdmin just include "_get_foo" in the list_display.

class MyModelAdmin(admin.ModelAdmin):
list_display = ("_get_foo", "some_other_column, )

--
Norman J. Harman Jr.
Senior Web Specialist, Austin American-Statesman
___________________________________________________________________________
You've got fun! Check out Austin360.com for all the entertainment
info you need to live it up in the big city!

Paul Winkler

unread,
Aug 1, 2008, 2:44:06 PM8/1/08
to Django users
Thanks Norman, that works great!

Thanks also Martin for the kind help, I would've tried your solution
next but Norman's was easier.

--
PW

Martin Diers

unread,
Aug 1, 2008, 6:07:57 PM8/1/08
to django...@googlegroups.com

Hey, I'm thrilled there's an easier way. I don't like extra work
either. I'll have to look into this some more.

Martin Diers

unread,
Aug 1, 2008, 6:25:25 PM8/1/08
to django...@googlegroups.com
> In your model add method like this:
>
> def _get_foo(self):
> return self.the_display_column
> _get_foo.short_description = "Whatever"
> _get_foo.admin_order_field = "the_sort_column"
>
> Django looks for those special method attributes. More info here
> http://www.djangoproject.com/documentation/admin/

Ah! I missed that admin_order_field bit. That was the only reason I
haven't been using functions that way - they wouldn't sort.

Thanks Norman!


Reply all
Reply to author
Forward
0 new messages