当前位置: 首页 > 面试题库 >

具有OuterRef的简单子查询

杜昆琦
2023-03-14
问题内容

我正在尝试使用一个非常简单的Subquery方法OuterRef(不是出于实际目的,而是为了使其正常工作),但是我一直遇到相同的错误。

posts/models.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 shell

>>> 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()试图评估查询集并返回计数。

因此,人们可能会认为正确的方法是使用Count()替代方法。也许是这样的:

Post.objects.annotate(
    count=Count(Tag.objects.filter(post=OuterRef('pk')))
)

这不能工作有两个原因:

  1. 查询集Tag选择所有Tag字段,而Count只能依靠一个字段。因此:Tag.objects.filter(post=OuterRef('pk')).only('pk')是必需的(选择依靠tag.pk)。

  2. Count本身不是一个Subquery类,Count而是一个Aggregate。因此,由生成的表达式Count不能识别为SubqueryOuterRef需要子查询),我们可以使用来解决Subquery

应用1)和2)的修复程序将产生:

Post.objects.annotate(
    count=Count(Subquery(Tag.objects.filter(post=OuterRef('pk')).only('pk')))
)

但是, 如果您检查正在生成的查询:

SELECT 
    "tests_post"."id",
    "tests_post"."title",
    COUNT((SELECT U0."id" 
            FROM "tests_tag" U0 
            INNER JOIN "tests_post_tags" U1 ON (U0."id" = U1."tag_id") 
            WHERE U1."post_id" = ("tests_post"."id"))
    ) AS "count" 
FROM "tests_post" 
GROUP BY 
    "tests_post"."id",
    "tests_post"."title"

您会注意到一个GROUP BY条款。这是因为COUNT是聚合html" target="_blank">函数。现在它不会影响结果,但是在其他情况下可能会影响结果。这就是为什么文档提出了一种不同的方法的原因,该方法是subquery通过特定的values+
annotate+组合将聚合移动到中values

Post.objects.annotate(
    count=Subquery(
        Tag.objects
            .filter(post=OuterRef('pk'))
            # The first .values call defines our GROUP BY clause
            # Its important to have a filtration on every field defined here
            # Otherwise you will have more than one group per row!!!
            # This will lead to subqueries to return more than one row!
            # But they are not allowed to do that!
            # In our example we group only by post
            # and we filter by post via OuterRef
            .values('post')
            # Here we say: count how many rows we have per group 
            .annotate(count=Count('pk'))
            # Here we say: return only the count
            .values('count')
    )
)

最终将产生:

SELECT 
    "tests_post"."id",
    "tests_post"."title",
    (SELECT COUNT(U0."id") AS "count" 
            FROM "tests_tag" U0 
            INNER JOIN "tests_post_tags" U1 ON (U0."id" = U1."tag_id") 
            WHERE U1."post_id" = ("tests_post"."id") 
            GROUP BY U1."post_id"
    ) AS "count" 
FROM "tests_post"


 类似资料:
  • 问题内容: 最近,我一直在使用嵌套集模型中的废话。我喜欢为几乎所有有用的操作和视图设计查询。我坚持的一件事是如何选择节点的直接子代(并且 仅 选择子代,而不是进一步的子代!)。 老实说,我确实知道一种方法-但它涉及大量的SQL。我敢肯定有一个更直接的解决方案。 问题答案: 您是否阅读过您张贴的文章?在“查找节点的直接下属”标题下 但是,我要做的(这是作弊)是将嵌套集与邻接列表结合在一起-我在表中嵌

  • 问题内容: T-SQL查询 上面查询的LINQ to Entities替代 在stackoverflow上有很多复杂的子查询,我只想看一个简单的例子,说明如何通过linq完成一个简单的子查询。 问题答案: 简单的答案是使用 “ let” 关键字并生成一个子查询,该查询支持您的主要实体的条件集。 这将在TSQL中创建一个存在块,类似于 它接近您的要求,通常会在SQL Server上创建相同的查询计划

  • 问题内容: 我试图在我的简单GUI上显示一些卡,但是没有显示。 我已使用要上传的.gif上传了一个工作文件,该代码已关闭但不正确。 http://www.filedropper.com/cardgameproblem大小:0Kb,类型:.zip 包含1个.py和1个.gif 要看的线始于257-266。我知道这只是一个小错误,但我看不到它。 请帮忙 问题答案: 经过一番修补,我发现当将图像存储在G

  • 本文向大家介绍对MySQL子查询的简单改写优化,包括了对MySQL子查询的简单改写优化的使用技巧和注意事项,需要的朋友参考一下 使用过oracle或者其他关系数据库的DBA或者开发人员都有这样的经验,在子查询上都认为数据库已经做过优化,能够很好的选择驱动表执行,然后在把该经验移植到mysql数据库上,但是不幸的是,mysql在子查询的处理上有可能会让你大失所望,在我们的生产系统上就由于碰到了这个问

  • 我正在尝试向我的菜单项(messageViewMenu)添加一个视图(messageView),这样当点击菜单项时,这个新视图就会添加到它的正上方,它们会一个接一个地在屏幕上向下滑动-Evernote 5.1.2有类似的功能。 我使用NSLayoutConstraint将新视图附加到我假定的菜单项顶部。然后,我将菜单项的现有垂直约束设置为标题UIView(\u headerMessageConst

  • 本文向大家介绍WordPress 简单的例子,包括了WordPress 简单的例子的使用技巧和注意事项,需要的朋友参考一下 示例 这个过滤器非常有用。开发人员的常见问题之一是如何在他们开发的插件中包含模板。 在wordpress使用wp层次结构在活动的子主题/父主题中找到适当的模板后,将立即应用该过滤器。 小心定义何时要修改模板路径。在下面的示例中,代码检查以查看当前页面是否是我们的自定义帖子类型