| | 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 | }}} |