Version 1 (modified by davidschein@…, 8 years ago) (diff)


There are times when a Char field can have number and alpha values and you want them sorted such that the numbers come out in numeric rather than alphanumeric order followed by the text values.

For example, academic course sections may be named 1, 2, 14, A, B, C, and so on (not my decision, I should add.) So we have

class Section(models.Model):
    name = models.CharField(maxlength=3)
    schedule_course = models.ForeignKey(ScheduleCourse)
    instructors = models.ManyToManyField(Contact)

When we list the sections we want to see something like:

2	LEC: W	6:30pm-9:20pm	
14	LEC: Th	6:30pm-9:20pm	
A	LEC: M W F	10:00am-10:50am	
B	LEC: M W F	11:00am-11:50am	

rather than the alphanumerically ordered:

14	LEC: Th	6:30pm-9:20pm	
2	LEC: W	6:30pm-9:20pm	
A	LEC: M W F	10:00am-10:50am	
B	LEC: M W F	11:00am-11:50am	

We accomplish this with a template tag as in {% for section in sc.section_set.all|sorted_int_then_alpha:"name" %}.

The code for sorted_int_then_alpha follows:

from django import template
from itertools import chain
from operator import attrgetter

register = template.Library()

def sorted_int_then_alpha(items, attr):
    """ Return items sorted on attr where int values come first and 
        in numerical order followed by anything else in aplhanumeric ordering
    key = attrgetter(attr)
    sorted_ints = sorted([(int(key(item)),item) for item in items if])
    sorted_strs = sorted([(key(item),item) for item in items if not])
    return [item for (_sorter, item) in chain(sorted_ints, sorted_strs)]