我试图创建一个非常简单的子查询,它使用OuterRef(不是为了实际目的,只是为了让它工作),但仍然会遇到相同的错误。
柱/模型.py
from django.db import models
class Tag(models.Model):
name = models.CharField(max_length=120)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=120)
tags = models.ManyToManyField(Tag)
def __str__(self):
return self.title
manage.py外壳代码
>>> from django.db.models import OuterRef, Subquery
>>> from posts.models import Tag, Post
>>> tag1 = Tag.objects.create(name='tag1')
>>> post1 = Post.objects.create(title='post1')
>>> post1.tags.add(tag1)
>>> Tag.objects.filter(post=post1.pk)
<QuerySet [<Tag: tag1>]>
>>> tags_list = Tag.objects.filter(post=OuterRef('pk'))
>>> Post.objects.annotate(count=Subquery(tags_list.count()))
最后两行应该给出每个Post对象的标记数。在这里我不断地得到同样的错误:
ValueError: This queryset contains a reference to an outer query and may only be used in a subquery.
示例中的一个问题是不能将
queryset.count()
用作子查询,因为.count()
尝试计算queryset并返回计数。因此,人们可能认为正确的方法是使用
Count()
。可能是这样的:这不起作用有两个原因:
查询集
Tag
选择所有Tag
字段,而Count
只能在一个字段上计数。因此:Tag.objects.filter(post=OuterRef('pk')).only('pk')
是必需的(选择依赖于tag.pk
)。Count
本身不是一个Subquery
类,Count
是一个Aggregate
。因此,由Count
生成的表达式不被识别为Subquery
(OuterRef
需要子查询),我们可以使用Subquery
修复该问题。对1)和2)应用修复程序将产生:
但是 如果检查正在生成的查询
您可能会注意到我们有一个
GROUP BY
子句。这是因为Count是一个聚合,现在它不影响结果,但在其他一些情况下它可能会影响结果。这就是为什么docs建议了一种稍微不同的方法,即通过values
+annotate
+values
的特定组合将聚合移入subquery
最后,这将产生:
django-sql-utils包使这种子查询聚合变得简单。只要
pip install django-sql-utils
然后:SubqueryCount的API与Count相同,但它在SQL中生成一个子选择,而不是加入相关表。
相关问题 更多 >
编程相关推荐