【问题标题】:"Cannot update a query once a slice has been taken". Best practices?“一旦获取切片,就无法更新查询”。最佳实践?
【发布时间】:2016-05-14 09:17:46
【问题描述】:

由于我项目的性质,我发现自己经常从查询集中取出切片,如下所示:

Thread.objects.filter(board=requested_board_id).order_by('-updatedate')[:10]

但这给我留下了实际使用我选择的元素做事情的问题,因为任何类型的 .update() 或 .filter() 在切片后都不起作用。

我知道有几种绕过它的方法,但它们都很混乱和令人困惑,并且严重降低了代码的可读性,尤其是当我不得不经常这样做的时候。

绕过这个切片过滤器限制的最佳方法是什么?

【问题讨论】:

  • 这有点宽泛。您能否举例说明您想要对其进行的操作,以及您当前的一些我们可能能够改进的解决方法?
  • 例如:Thread.objects.filter(board=requested_board)[:5].update(title='whatever')。如果不是 [:5] 切片,这将起作用。当前的解决方法包括使用itertools.chain,但这会返回一个itertools 对象,然后必须将其转换为列表,甚至可以从视图中作为模板上下文发送。有效,但它非常混乱且难以阅读。
  • This answer 涵盖了这种情况,这也是我的建议。获取过滤和切片查询集的 ID(使用 value_list 或类似的),然后将它们重新插入以使用 update 形成新查询。有点难看,但不是 Django 的错,正如那里解释的那样(UPDATE... WHERE... LIMIT... 在 SQL 中不行)。
  • @Two-BitAlchemist 实际上你可以简化它 - 你不需要获取 ID,你可以直接将查询集传递给 filter(id__in=sliced_queryset)
  • 不,它会通过子查询来实现:仍然会影响性能,但不如整个其他查询。

标签: python django


【解决方案1】:

到目前为止,根据 cmets,我发现 Daniel Roseman 的这个解决方案是最不“丑陋”的:

sliced_queryset = Somemodel.objects.filter(field='fieldvalue')[:5]

然后使用id__in= 引用切片查询集对象的ID:

Somemodel.objects.filter(id__in=sliced_queryset).update(field_to_update='whatever')

效果很好,我刚试过。

我希望 Django 有一种更“直接”的方式来执行此操作,但它仍然非常简单。如果有人有更好的方法,请发布,我会将您的答案标记为正确。


作为一个额外的建议,如果你使用它来增加一个字段,比如一个“视图”字段,你可以像这样干净地自我引用它:

from django.db.models import F

Somemodel.objects.filter(id__in=sliced_queryset).update(views=F('views')+1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-16
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 2013-05-10
    • 1970-01-01
    相关资源
    最近更新 更多