【问题标题】:Custom ordering in DjangoDjango中的自定义排序
【发布时间】:2010-10-27 09:10:40
【问题描述】:

如何在 Django QuerySets 中定义特定的排序?

具体来说,如果我有这样的QuerySet['a10', 'a1', 'a2']

常规订单(使用Whatever.objects.order_by('someField'))会给我['a1', 'a10', 'a2'],而我正在寻找:['a1', 'a2', 'a10']

定义我自己的排序技术的正确方法是什么?

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    据我所知,没有办法以这种方式指定数据库端排序,因为它过于特定于后端。您可能希望求助于老式的 Python 排序:

    class Foo(models.Model):
        name = models.CharField(max_length=128)
    
    Foo.objects.create(name='a10')
    Foo.objects.create(name='a1')
    Foo.objects.create(name='a2')
    
    ordered = sorted(Foo.objects.all(), key=lambda n: (n[0], int(n[1:])))
    print ordered # yields a1, a2, 10
    

    如果您发现自己经常需要这种排序,我建议您为执行排序的模型创建一个自定义 models.Manager 子类。比如:

    class FooManager(models.Manager):
        def in_a_number_order(self, *args, **kwargs):
            qs = self.get_query_set().filter(*args, **kwargs)
            return sorted(qs, key=lambda n: (n[0], int(n[1:])))
    
    class Foo(models.Model):
        ... as before ...
        objects = FooManager()
    
    print Foo.objects.in_a_number_order()
    print Foo.objects.in_a_number_order(id__in=[5, 4, 3]) # or any filtering expression
    

    【讨论】:

    • 尝试此方法时出现此错误: : 'Model' object is unindexable
    • sorted 是否返回查询集?鉴于它传递了一个查询集,我会这样认为,但我认为它也可能被转换为列表或内部的东西进行排序,然后返回 that
    • 恐怕sorted 没有返回查询集;它是一个内置的python函数,所以它对Django一无所知。 Django 的查询集实现了 python 的可迭代接口,所以sorted 能够处理它们,因为它认为它刚刚传递了一个列表。如果您需要返回一个 QS,AFAIK 没有简单的方法可以从排序返回的列表中创建一个 QS... 可以伪造一个 QS(基本上实现其接口),但这可能很棘手。有很多 Manager 方法不返回 QS,恐怕这个排序功能会与那些一致。
    【解决方案2】:

    这取决于你想在哪里使用它。

    如果您想在自己的模板中使用它,我建议您编写一个模板标签,它将为您完成排序 在其中,您可以使用任何您想使用的排序算法。

    在管理员中,我通过将模板扩展到我的需要并加载模板标签来进行自定义排序,如上所述

    【讨论】:

      【解决方案3】:

      @Jarret 的回答(在 Python 中进行排序)非常适合简单的情况。只要您有一个大表,并且想只提取以某种方式排序的结果的第一页,这种方法就会中断(您必须先从数据库中提取每一行,然后才能进行排序)。那时我会考虑添加一个非规范化的“排序”字段,您可以在保存时从“名称”字段填充该字段,您可以按照通常的方式在数据库级别进行排序。

      【讨论】:

      • +1 用于解决与性能相关的问题;实际上,您的建议是我们在与数据库无关的环境中用于报告的一些数据中使用的建议,并且我们有数千万行,所以我可以保证它运行良好.
      【解决方案4】:

      如果您有更大的数据集并另外使用 SOLR 后端(例如使用 Haystack):

      使用solr.ICUCollationFieldnumeric=true 选项作为排序字段的类型。这将根据语言进行排序,如果存在数字,将根据数字规则而不是字符串排序对数字部分进行排序。

      见: https://cwiki.apache.org/confluence/display/solr/Language+Analysis#LanguageAnalysis-UnicodeCollation http://www.solr-start.com/javadoc/solr-lucene/org/apache/solr/schema/ICUCollationField.html

      【讨论】:

        猜你喜欢
        • 2016-02-03
        • 2019-05-19
        • 1970-01-01
        • 1970-01-01
        • 2018-09-28
        • 2016-12-05
        • 2011-04-07
        • 2022-10-05
        • 1970-01-01
        相关资源
        最近更新 更多