views:

109

answers:

2

Consider this sample model:

MODEL_CHOICES = ( (u"SPAM", u"Spam"), (u"XOUP", u"Eggsoup"), )

(snip)

type = models.CharField(max_length=4, choices=MODEL_CHOICES)

(The actual implementation is domain-specific and in non-English, so this sample has to do.)

When building my query, I'd like to sort the results by that type field, and present the results to the user. Naturally, I'd like to sort by the display name of that field.

Something along the lines of:

documents = MyModel.objects.filter(...).order_by("type")

However, [query-set].order_by([field]) only allows sorting by field name, which will result in SPAM < XOUP (to the machine) even though Eggsoup < Spam (to the human reader).

Consider this set of instances sorted by type:

Name | Type

obj1 | SPAM

obj2 | SPAM

obj3 | SPAM

obj4 | XOUP

obj5 | XOUP

But this is the order the user will see, i.e. the user will see the display name, not the internal field value of the type column:

Name | Type

obj1 | Spam

obj2 | Spam

obj3 | Spam

obj4 | Eggsoup

obj5 | Eggsoup

Which in the eyes of the human user is not sorted correctly.

Is there a feature in Django that allows sorting by display name? Or a way to accomplish this "manually"? (Renaming the choices so that the display name has the same order as the actual values is not an option.)

A: 

Assuming the display name comes from the model as well then you can sort by that field to order the choices like you want.

MODEL_CHOICES = MyModel.objects.all().values_list('value_field', 'display_field').order_by('display_field')
...
type = models.CharField(max_length=4, choices=MODEL_CHOICES)

If the choices are a constant like in your question then you can simply change the order in the constant.

MODEL_CHOICES = ((u"XOUP", u"Eggsoup"), (u"SPAM", u"Spam"), )

In the end the choices is just a list of tuples so you can sort with normal Python sort. The Python wiki has a nice example of sorting a list of tuples on the second element.

Mark Lavin
Mark, thanks for your answer. However, it's not about the sort order of the choices but about the order of the results. I have edited the original question to clarify the point.
prometheus
It still isn't clear to me where you are getting the display name from. Is that part of the model?
Mark Lavin
It's a feature of Django - when you define the choices as two-tuples, the first item becomes the actual value stored in the table, and the second item is the display name, which, for instance, is being used in the admin or when creating forms from the model. See here:http://www.djangoproject.com/documentation/models/choices/
prometheus
Yes, I understand that. My question is how are you defining the choices? Are you defining them as a constant or are you generating the choice from a queryset?
Mark Lavin
I am definining them as constants. Still, re-ordering them in the model does not solve the above.
prometheus
A: 

If the result sets are small enough, you could do an in-memory sort of results in code. I can't think of any decent way to sort the results in database level. It certainly would be possible if you used stored procedure which is aware of display names, however you'd have to write raw sql. As for manual sorting- you can use something like this:

obj_list = list(Model.objects.all())
import operator
obj_list.sort(key=operator.methodcaller('get_foo_display'))

Here are some nice examples on how to sort lists in Python: http://wiki.python.org/moin/HowTo/Sorting

fest
Thanks. The operator usage looks nifty, I wasn't aware of it.
prometheus