13

我有以下型号:

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 "visible" = false WHERE "app_work"."id" IN (SELECT...

如果我删除更新子句,查询运行没有问题并返回我所期望的。

看起来此错误发生在带有注释后跟更新的查询中。有没有其他方法可以写这个?

4

4 回答 4

11

在没有制作一个能够复制您的问题并尝试解决方案的玩具数据库的情况下,我至少可以建议Django 中的方法:获取查询集的补充作为一种可能的方法。

试试这个方法:

qs.annotate(Count('book')).filter(Q(book__count__gt=1))
Work.objects.filter(pk__in=qs.values_list('pk', flat=True)).update(visible=False)
于 2012-11-26T07:01:00.650 回答
7

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

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

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

于 2017-04-07T15:33:51.267 回答
2

添加到 Oli 的答案:如果您需要更新注释,则首先执行过滤器并将结果存储在变量中,然后在该查询集上调用不带参数的过滤器来访问update函数,如下所示:

q = X.objects.filter(annotated_val=5, annotated_name='Nima')
q.query.annotations.clear()
q.filter().update(field=900)
于 2017-04-20T15:26:32.817 回答
1

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

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

于 2015-07-23T20:35:43.543 回答