【问题标题】:Natural sort on Django QuerysetDjango Queryset 上的自然排序
【发布时间】:2017-03-01 15:16:36
【问题描述】:

我正在开发一个系统,该系统列出了按产品代码排序的一系列产品。产品代码由两个字母组成,后跟一个数字,例如 EG1。

我目前通过做一个简单的排序这些产品

Product.objects.order_by('product_code'),

但是,由于可以有多个数字的产品代码(例如 EG12),这些代码将在单个数字代码之前出现。 即 EG1、EG11、EG12、EG13 ... EG19、EG2、EG20 等

我知道在产品代码中添加前导零可以解决此问题(即 EG01 而不是 EG1),但由于已经有印刷文献和使用 EG1 的现有网站,这不是一个选项。

有没有办法解决这个问题,以正确的顺序显示这些产品?

【问题讨论】:

标签: python django natural-sort


【解决方案1】:

我认为这里的实现 (https://github.com/nathforge/django-naturalsortfield) 应该可以工作。这种方法的主要优点是它不在 python 中而是在数据库中进行排序,因此即使在大型数据集上它也能很好地执行,但会增加一些存储空间。

您必须更改模型以包含 product_code__sort 字段

class MyModel(models.Model):
    title = models.CharField(max_length=255)
    title_sort = NaturalSortField('title')

NaturalSortField 定义为

class NaturalSortField(models.CharField):
    def __init__(self, for_field, **kwargs):
        self.for_field = for_field
        kwargs.setdefault('db_index', True)
        kwargs.setdefault('editable', False)
        kwargs.setdefault('max_length', 255)
        super(NaturalSortField, self).__init__(**kwargs)

    def pre_save(self, model_instance, add):
        return self.naturalize(getattr(model_instance, self.for_field))

    def naturalize(self, string):
        def naturalize_int_match(match):
            return '%08d' % (int(match.group(0)),)

        string = string.lower()
        string = string.strip()
        string = re.sub(r'^the\s+', '', string)
        string = re.sub(r'\d+', naturalize_int_match, string)

        return string

【讨论】:

  • 我试过这个,但在 makemigrations 上出现以下错误:TypeError: __init__() missing 1 required positional argument: 'for_field'
  • 你用的是什么版本的 django?
  • 我使用的是 django 2.1.5
  • 您可以尝试将原始字段的名称传递给 NaturalSortField 吗?我已更新我的答案以反映所需的更改
  • 我添加了原始字段,但仍然出现错误:TypeError:无法在 core.Sggl 上重建字段 house_number_sort。Sggl:__init__() 缺少 1 个必需的位置参数:'for_field'
【解决方案2】:

试试这个

def alphanumeric_sort(objects_list, sort_key):
    """ Sort a list of objects by a given key
    This function sort a list of objects by a given
    key common across the objects
    Sorting can be implemented on keys that are either
    alphabets, integers or both
    """
    convert = lambda text: int(text) if text.isdigit() else text
    alphanum_key = lambda key: [
        convert(c) for c in re.split("([0-9]+)", getattr(key, sort_key))
    ]
    return sorted(objects_list, key=alphanum_key)

【讨论】:

    猜你喜欢
    • 2011-04-07
    • 2021-02-28
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    • 2019-07-28
    • 2018-05-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多