| 1 | 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. |
| 2 | |
| 3 | 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 |
| 4 | {{{ |
| 5 | #!python |
| 6 | class Section(models.Model): |
| 7 | name = models.CharField(maxlength=3) |
| 8 | schedule_course = models.ForeignKey(ScheduleCourse) |
| 9 | instructors = models.ManyToManyField(Contact) |
| 10 | ... |
| 11 | }}} |
| 12 | |
| 13 | When we list the sections we want to see something like: |
| 14 | {{{ |
| 15 | 2 LEC: W 6:30pm-9:20pm |
| 16 | 14 LEC: Th 6:30pm-9:20pm |
| 17 | A LEC: M W F 10:00am-10:50am |
| 18 | B LEC: M W F 11:00am-11:50am |
| 19 | }}} |
| 20 | rather than the alphanumerically ordered: |
| 21 | {{{ |
| 22 | 14 LEC: Th 6:30pm-9:20pm |
| 23 | 2 LEC: W 6:30pm-9:20pm |
| 24 | A LEC: M W F 10:00am-10:50am |
| 25 | B LEC: M W F 11:00am-11:50am |
| 26 | }}} |
| 27 | |
| 28 | We accomplish this with a template tag as in {{{{% for section in sc.section_set.all|sorted_int_then_alpha:"name" %}}}}. |
| 29 | |
| 30 | The code for {{{sorted_int_then_alpha}}} follows: |
| 31 | {{{ |
| 32 | #!python |
| 33 | from django import template |
| 34 | from itertools import chain |
| 35 | from operator import attrgetter |
| 36 | |
| 37 | register = template.Library() |
| 38 | |
| 39 | @register.filter |
| 40 | def sorted_int_then_alpha(items, attr): |
| 41 | """ Return items sorted on attr where int values come first and |
| 42 | in numerical order followed by anything else in aplhanumeric ordering |
| 43 | """ |
| 44 | key = attrgetter(attr) |
| 45 | sorted_ints = sorted([(int(key(item)),item) for item in items if item.name.isdigit()]) |
| 46 | sorted_strs = sorted([(key(item),item) for item in items if not item.name.isdigit()]) |
| 47 | return [item for (_sorter, item) in chain(sorted_ints, sorted_strs)] |
| 48 | }}} |