In Django, how can I order multiple choice CharField in random alphabetical order?

Imagine a Shirts model with size CharField whose values ​​are limited by a small number of options, for example. "small", "medium", "large", "large", etc.

To get shirts grouped by size, you would do:

 Shirts.objects.order_by('size') 

But Django will (naturally) sort the groups in alphabetical order, that is, “large” and then “medium” and then “small” and then “xlarge”. I want to have small to medium to large, etc.

those. what I naturally want to do is something like the following pseudocode:

 size_order = {'small': 1, 'medium': 2, 'large': 3, 'xlarge': 4} Shirts.objects.order_by('size_order[size]') 

What is the best way to accomplish this?

EDIT: See my comments on the answers below for thoughts on the various approaches proposed. I came across a Manager / QuerySet user approach using the SQL ORDER BY CASE syntax that I am learning.

+7
source share
5 answers

I realized that the closest thing to what I am looking for is to use the QuerySet.extra() method to use the SQL CASE WHEN / THEN syntax that Django does not directly support:

 CASE_SQL = '(case when size="small" then 1 when size="medium" then 2 when size="large" then 3 when size="xlarge" then 4 end)' Shirt.objects.extra(select={'shirt_order': CASE_SQL}, order_by=['shirt_order']) 

This may seem redundant and / or mucky, given my (artificial) example, but this is the trick I was looking for! Thanks to everyone for other well-grounded approaches to this problem, which somehow indirectly led me to understand this approach.

PS It's tempting to create a custom Manager / QuerySet model that provides a more custom Django interface for this kind of custom order using the SQL CASE WHEN / THEN syntax, but I will leave it as homework for myself at another time!

NOTE. The syntax of CASE WHEN / THEN is database specific. The syntax above is for SQLite. For PostgreSQL, omit the parentheses and use isolated quotes instead of double quotes.

+7
source

You must customize your size field by selecting the tuples ordered as you want. In your models.py you have something like:

 from django.db import models SHIRT_SIZE_CHOICES = ( (u"0", u"small"), (u"1", u"medium"), (u"2", u"large"), (u"3", u"xlarge")) class Shirt(models.Model): ... size = models.CharField(max_length=2, choices=SHIRT_SIZE_CHOICES) 

Then order_by will sort them as you wish.

+2
source

It sounds like you don't want to hardcode the possible options (because you used charfield), but at the same time you say that there are a small number of options.

If you are content with a hard code of choice, you can instead change to a whole field:

 class Shirt(models.Model): SIZE_CHOICES = ( (1, u'small'), (2, u'medium'), (3, u'large'), (4, u'x-large'), (5, u'xx-large'), ) size = models.IntegerField(choices = SIZE_CHOICES) 

If you do not want to hardcode the sizes, then you probably want to move the available sizes to a separate model and refer to it as a foreign key from your Shirt model. To make it an arbitrary sort, you will need an index of some other type besides the primary key, which you can sort. Maybe something like this:

 class Size(models.Model): sortorder = models.IntegerField() name = models.CharField() class Meta: ordering = ['sortorder'] 
+2
source

Without writing a custom sort function, just snap to the order field on the model.

 class Shirt(models.Model): ... order = models.IntegerField(default=0) class Meta: ordering = ('order',) Shirt.objects.filter(name='Awesome Shirt') 

Or, in a more appropriate way, create a new model called Size .

+2
source

If you do not want to store the field values ​​as integers, then the built-in order_by () method will not be able to handle your own case. You will need to create your own function to sort the data after receiving it.

And for this, of course, the best way would be to match your arbitrary values ​​to integers in the appropriate order, and then sort by this scheme :).

+1
source

All Articles