【问题标题】:django - reorder queryset after slicing itdjango - 切片后重新排序查询集
【发布时间】:2010-10-30 15:44:46
【问题描述】:

我从一个按日期时间字段排序的 Foo 模型中获取最新的 5 行。

qs = Foo.objects.all()[:5]

在接下来的步骤中,我想通过其他一些条件(实际上,按相反方向的相同日期时间字段)对查询集进行重新排序。但是不允许在切片后重新排序。 reverse() 撤消第一个排序,给我一个不同的查询集。有没有办法在不从查询集中创建列表并使用它进行排序的情况下完成我想要的事情?

【问题讨论】:

    标签: django django-queryset django-orm


    【解决方案1】:

    不,没有办法做到这一点。 order_by 是对数据库的操作,但是当您对查询集进行切片时,它会被评估并且之后不会返回到数据库。

    听起来您已经知道解决方案了:在评估的 qs 上运行 reversed()

    qs = reversed(Foo.objects.all()[:5])
    

    【讨论】:

    • 所以我没有错过任何东西。谢谢。
    • 我遇到了同样的问题,按照 Daniel 的建议,但发现我无法在查询集上使用 count 方法
    • 在 python 文档中找不到对 reversed() 的引用,您可以提供任何链接吗?
    【解决方案2】:

    order_by 为您提供 SQL 数据库内排序。您已经在使用它,然后对其进行切片。此时,结果将被检索到内存中。如果你想改变它们的顺序,你需要使用 Python 的内存排序来完成,而不是 ORM 的数据库排序。

    在你的情况下,丹尼尔已经给出了最好的解决方案:因为你只是想按相同的字段排序,但是以其他顺序,只需反转你拥有的列表:

    qs = Foo.objects.all()[:5]
    objs = reversed(qs)
    

    如果您想按其他字段排序,那么您可以使用 sorted() 函数和自定义键函数:

    qs = Foo.objects.all()[:5]
    objs = sorted(qs, key=lambda o: o.some_other_field)
    

    【讨论】:

    • 是的,我知道 order_by 是数据库排序。但我发现有趣的是,切片后的 reverse()(queryset 方法)正在工作,并且它重新执行查询,给出了意想不到的结果。
    • 当您从查询集中提取结果时,它仍然是有效的查询集。如果你修改它(例如,通过添加 reverse()),它会重新评估它。
    【解决方案3】:

    迟到的答案,但这对我有用:

    import random
    sorted(queryset[:10], key=lambda x: random.random())
    

    【讨论】:

      猜你喜欢
      • 2015-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-22
      • 2011-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多