Reputation: 18262
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
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
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
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
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
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