如何更新已注释的查询集?

时间:2012-11-26 06:48:49

标签: django orm

我有以下型号:

class Work(models.Model):
    visible = models.BooleanField(default=False)

class Book(models.Model):
    work = models.ForeignKey('Work')    

我试图像这样更新一些行:

qs=Work.objects.all()
qs.annotate(Count('book')).filter(Q(book__count__gt=1)).update(visible=False)

然而,这是一个错误:

DatabaseError:子查询包含太多列 第1行:... SET“可见”= false WHERE“app_work”。“id”IN(SELECT ...

如果删除update子句,查询运行没有问题,并返回我期望的内容。

对于带有注释后跟更新的查询,似乎会发生此错误。有没有其他方式来写这个?

4 个答案:

答案 0 :(得分:10)

如果没有让玩具数据库能够复制您的问题并尝试解决方案,我至少可以建议Django: Getting complement of queryset中的方法作为一种可能的方法。

尝试这种方法:

qs.annotate(Count('book')).filter(Q(book__count__gt=1))
Work.objects.filter(pk__in=qs.values_list('pk', flat=True)).update(visible=False)

答案 1 :(得分:5)

您还可以非常简单地清除查询集中的注释:

qs.query.annotations.clear()
qs.update(..)

这意味着您只会触发一个查询,而不是一个查询,但如果您的查询依赖于要过滤的注释,请不要使用此项。这很棒用于删除数据库生成的连接,以及偶尔添加到模型的默认查询中的实用程序垃圾...但问题中的示例是一个完美的示例,说明这不起作用。

答案 2 :(得分:1)

我已经重复了这个问题&相信它是Django ORM的一个bug。 @acjay答案是一个很好的解决方法。错误报告:https://code.djangoproject.com/ticket/25171

在Django 2 alpha中发布的修补程序:https://code.djangoproject.com/ticket/19513

答案 3 :(得分:1)

要添加到Oli的答案:如果需要更新注释,请先执行过滤,然后将结果存储在变量中,然后调用该查询集中没有参数的过滤器来访问{{1}像这样的函数:

update