diff -r d3a5d0d95869 roundup/cgi/templating.py --- a/roundup/cgi/templating.py Sat Mar 27 13:05:50 2021 -0400 +++ b/roundup/cgi/templating.py Sun Mar 28 10:42:06 2021 -0400 @@ -2595,10 +2595,33 @@ l.reverse() return self.viewableGenerator(l) - def sorted(self, property, reverse=False): + def sorted(self, property, reverse=False, NoneFirst=False): """ Return this multilink sorted by the given property """ + + # use 2 if NoneFirst is False to sort None last + # 0 to sort to sort None first + NoneCode = (2,0)[NoneFirst] + def keyfunc(v): + # Return tuples made of (group order (int), base python + # type) to sort function. + # Do not return v[property] as that returns an HTMLProperty + # type/subtype that throws an exception when sorting + # python type (int. str ...) against None. + val = v[property]._value + if val: + return (1, val) # val should be base python type + elif val is None: + return (NoneCode, None) + value = list(self.__iter__()) - value.sort(key=lambda a:a[property], reverse=reverse) + + value.sort(key=keyfunc, reverse=reverse) + # ORIG: value.sort(key=lambda a:a[property], reverse=reverse) + #cls = self._db.getclass(self._prop.classname) + #sort_repr = cls.properties[property].sort_repr + #value.sort(key=lambda a:sort_repr(cls, a[property]._value, + # property), + # reverse=reverse) return value def __contains__(self, value):