【问题标题】:How do I store version number strings in a django database so they are correctly comparable/sortable如何将版本号字符串存储在 django 数据库中,以便它们可以正确比较/可排序
【发布时间】:2015-01-29 06:39:44
【问题描述】:

我正在开发/维护/管理从各种可穿戴研究设备收集的测试结果数据库。每个设备都有三个主要组件,每个组件都有两个版本号(固件和硬件)。我正在使用 django 应用程序为数据库提供 Web 界面。版本号表示为直整数或三元组(主要、次要、构建)。整数很容易处理,我显然可以将三元组存储为字符串,但作为字符串,它们将无法正确排序或正确比较,例如,如果我只想要固件版本低于 14.x.y 的设备产生的测试结果。

由于第二个“小数点”分隔符,我不能使用浮点数。我想也许可以通过将其存储为日期来进行黑客攻击,但这会将次要编号限制为小于 12 并将构建编号限制为小于 29,此外我知道这是一个糟糕的解决方案。我什至不应该承认自己曾想过。

没有用一些 PL/SQL 扩展数据库以提供正确处理字符串的比较函数,有没有简单的方法来做到这一点?如果没有,我什至可以在 django 中使用我的自定义 SQL 函数吗?

【问题讨论】:

  • 为什么不将其存储为字符串?
  • 因为 '10' 作为字符串排在 '2' 之前

标签: python mysql django tuples


【解决方案1】:

将它们存储为零填充字符串:

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

您始终可以通过这种零填充格式显示常规版本:

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

【讨论】:

  • 我正要建议这个。它不是很有效,但这是我看到的几个框架/库必须处理这个问题的方法,优点是 SQL 排序/比较“正常工作”。
  • 对,我考虑过这样做,但不确定如何确定要填充多少,因为这将涉及了解所有其他版本号的单个版本组件的最大长度数据库。再说一次,如果我们甚至有超过五位数的单个组件,我猜我们做错了。
【解决方案2】:

您要查找的内容称为“自然排序”。

实现这一点的另一种方法是使用数据库排序。这是 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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-16
    • 2022-07-08
    相关资源
    最近更新 更多