derekerdmann
derekerdmann

Reputation: 18262

Order model by field with choices

I'm trying to order models in a Django app using a field that has predefined choices. I can sort alphabetically, but since the choices are the days of the week, that doesn't quite match what I need. Here's the model:

class Slot( models.Model ):

    DAY_CHOICES = (
        ('SUN', 'Sunday'),
        ('MON', 'Monday'),
        ('TUE', 'Tuesday'),
        ('WED', 'Wednesday'),
        ('THU', 'Thursday'),
        ('FRI', 'Friday'),
        ('SAT', 'Saturday'),
    )

    day = models.CharField( max_length=3, choices=DAY_CHOICES )
    start = models.TimeField()
    end = models.TimeField()
    template = models.ForeignKey( Template )

And here's the inline that's pulling the model into an admin view:

class SlotInline( admin.TabularInline ):
    model = Slot
    ordering = ('day','start',)

I know I could probably use an integer as the stored value, but is there a general way to impose a custom sort order on a field with choices?

Upvotes: 1

Views: 1429

Answers (5)

Steven
Steven

Reputation: 2698

Quoting from the last paragraph of https://docs.djangoproject.com/en/dev/ref/models/fields/#field-choices:

But if you find yourself hacking choices to be dynamic, you're probably better off using a proper database table with a ForeignKey. choices is meant for static data that doesn't change much, if ever.

So I'd say the answer is no and you'd be better of with a separate Day model with a field for ordering

class Day(models.Model):
    name = models.CharField(max_length=9)
    ordering = models.PositiveIntegerField()

    class Meta:
        ordering = ['ordering']

Even though it feels like overkill for 7 items!

Upvotes: 1

okm
okm

Reputation: 23871

You could use extra, although the implementation might not be graceful and needs tweaking for complex query and different choices:

# generate 'WHEN foo THEN bar's
switch = ' '.join("WHEN '{}' THEN {}".format(x[0],i) for i,x in enumerate(Slot.DAY_CHOICES))
# basic queryset
Slot.objects.extra(select={'day_index':'CASE day {} END'.format(switch)}).order_by('day_index', 'start')

Upvotes: 0

sa3m
sa3m

Reputation: 101

Maybe you should look at this library: https://github.com/bigjason/django-choices

I don't know any basic to do such thing, unlike fields where you can specify a function name, you can't do that in ordering. The only special thing you can do is to specify get_ordering.

Upvotes: 0

Nathan
Nathan

Reputation: 1478

If you were writing your own view rather than using the admin view, you could potentially do the ordering in raw SQL. I've done this before in Oracle with something like:

ORDER BY decode(day, 'SUN', 0, 'MON', 1 )

I don't know how you'd fit that in with QuerySet.order_by() - maybe you'd need to use QuerySet.raw() to do the query with direct SQL.

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 600059

You should store the data as an integer (eg 0 = Sunday), and use the choices to map that integer to the day. Then sorting is simple.

Upvotes: 2

Related Questions