【问题标题】:sorting a query set after a for loop on it在 for 循环之后对查询集进行排序
【发布时间】:2019-10-23 12:39:22
【问题描述】:

我想对查询集中的所有对象应用一个方法,然后对它们进行排序。

products = Product.objects.all()
for product in products:
    product.update_exist_flag()

products = products.order_by('-exist_flag')

它引发了这个错误:

AssertionError: 获取切片后无法重新排序查询。

我该如何解决?

【问题讨论】:

  • 你能添加你如何创建产品对象的代码吗?
  • 好的,我已经添加了。 @JamesBurgess

标签: python django django-queryset


【解决方案1】:

您可能想阅读:When QuerySets are evaluated

for product in products::这里查询gets evaluated,即数据不在数据库中。之后,您将无法重新排序查询。


理想情况下,您应该再次执行相同的查询:

products = Product.objects.all()

for product in products:
    product.update_exist_flag()

products = Product.objects.all().order_by('-exist_flag')

但是,有一个技巧可以在不再次执行相同查询(不接触数据库)的情况下做到这一点:

products = Product.objects.all()

for product in products:
    product.update_exist_flag()

# This will return a list.
products = sorted(products, key=lambda p: p.exist_flag, reverse=True)    

正如@heemayl 在评论中提到的,如果exist_flag 是相关对象(数据库中表中的条目),那么它将再次命中数据库。在这种情况下,仍然可以进行一种优化,if你想根据exist_flag的id进行排序,那么我们可以使用p.exist_flag_id而不是p.exist_flag,这样就不会命中数据库。

【讨论】:

  • 反转一个非常大的数据集可能非常昂贵,所以我不推荐第二种方法。
  • 对!这就是我提到Ideally, you should do the same query again:的原因。
  • 如果exist_flag 是相关对象,它将再次访问数据库(除非您使用任何预取技术,例如select_related)。
【解决方案2】:

再次执行查询:

products = Product.objects.all()
for product in products:
    product.update_exist_flag()

products = Product.objects.all().order_by('-exist_flag')

一般来说,任何时候你想对模型执行任何操作,在数据库级别执行,它会比在 python 级别执行更快。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-22
    • 2018-07-29
    • 1970-01-01
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多