【问题标题】:Reorder Django QuerySet by dynamically added field通过动态添加的字段重新排序 Django QuerySet
【发布时间】:2017-09-14 11:19:24
【问题描述】:

有一段代码,它从数据库中获取一些查询集,然后将新的计算字段附加到查询集中的每个对象。不能通过注释添加此字段(因为它是遗留的,并且此计算基于另一个已经预取的数据)。

像这样:

from django.db import models
class Human(models.Model):
    name = models.CharField()
    surname = models.CharField()

def calculate_new_field(s):
   return len(s.name)*42

people = Human.objects.filter(id__in=[1,2,3,4,5])

for s in people:
   s.new_column = calculate_new_field(s)
# people.somehow_reorder(new_order_by=new_column)

所以现在 QuerySet 中的所有人都有一个新列。我想通过 new_column 字段对这些对象进行排序。 order_by() 显然不起作用,因为它是一个数据库选项。我知道我可以将它们作为排序列表传递,但是有很多模板和其他逻辑,期望从这个对象 QuerySet-like 接口与它的方法等等。

所以问题是:是否有一些不是很糟糕和肮脏的方法来通过动态添加的字段重新排序现有的 QuerySet 或使用这些数据创建新的类似 QuerySet 的对象?我相信我不是唯一一个面临这个问题的人,它已经用 django 解决了。但是我什么都找不到(除了添加第三方库,这也不是一个选项)。

【问题讨论】:

    标签: python django django-queryset


    【解决方案1】:

    从概念上讲,QuerySet 不是一个结果列表,而是“获取这些结果的指令”。它被懒惰地评估并被缓存。保存缓存结果的QuerySet的内部属性是qs._result_cache

    因此,for s in people 语句强制对查询进行评估并缓存结果。

    之后,您可以通过以下方式对结果进行排序:

    people._result_cache.sort(key=attrgetter('new_column'))

    但是,在评估 QuerySet 之后,保留 QuerySet 接口(在我看来)没有什么意义,因为许多操作会导致重新评估查询。从现在开始,您应该处理一个模型列表

    【讨论】:

      【解决方案2】:

      你可以试试functions.Length:

      from django.db.models.functions import Length
      
      qs = Human.objects.filter(id__in=[1,2,3,4,5])
      qs.annotate(reorder=Length('name') * 42).order_by('reorder')
      

      【讨论】:

      • 实际上我不是按长度排序列,这是一个计算出来的百分比。我只是用长度来说明添加的列基本上只是一个以某种方式计算出来的数字。对不起,如果我误导了你。
      • 如您所见,您可以添加计算来注释并将其用于订单,尝试显示您的真实代码
      猜你喜欢
      • 1970-01-01
      • 2023-03-31
      • 2015-11-25
      • 2019-07-04
      • 2018-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多