How do I store version number strings in a django database so they are correctly comparable/sortable

泪湿孤枕 提交于 2019-12-06 02:05:36

Store them as a zero-padded strings:

>>> def sortable_version(version):
...     return '.'.join(bit.zfill(5) for bit in version.split('.'))
... 
>>> sortable_version('1.1')
'00001.00001'
>>> sortable_version('2')
'00002'
>>> sortable_version('2.1.10')
'00002.00001.00010'
>>> sortable_version('10.1')
'00010.00001'
>>> sortable_version('2') > sortable_version('1.3.4')
True
>>> sortable_version('10') > sortable_version('2')
True
>>> sortable_version('2.3.4') > sortable_version('2')
True

And you can always show regular version from this zero-padded format:

>>> def normalize_version(padded_version):
...     return '.'.join(bit.lstrip('0') for bit in padded_version.split('.'))
... 
>>> normalize_version('00010')
'10'
>>> normalize_version('00002.00001.00010')
'2.1.10'

What you are looking for is called "natural sort".

Another way to implement this is to use database sorting. Here is an example for Postgres:

class VersionRecordManager(models.Manager):

    def get_queryset(self):
        return super().get_queryset().extra(
            select={
                'natural_version':
                    "string_to_array(                     "  
                    "   regexp_replace(                   "  # Remove everything except digits
                    "       version, '[^\d\.]+', '', 'g'  "  # and dots, then split string into
                    "   ), '.'                            "  # an array of integers.
                    ")::int[]                             "
            }
        )

    def available_versions(self):
        return self.filter(available=True).order_by('-natural_version')

    def last_stable(self):
        return self.available_versions().filter(stable=True).first()

class VersionRecord(models.Model):
    objects = VersionRecordManager()
    version = models.CharField(max_length=64, db_index=True)
    available = models.BooleanField(default=False, db_index=True)
    stable = models.BooleanField(default=False, db_index=True)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!