具有OuterRef的简单子查询 - python

我正在尝试制作一个使用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')))
)

这不能工作有两个原因:

  • Tag查询集选择所有Tag字段,而Count只能依靠一个字段。因此:需要Tag.objects.filter(post=OuterRef('pk')).only('pk')(以选择tag.pk计数)。
  • Count本身不是Subquery类,CountAggregate。因此,由Count生成的表达式不能识别为Subquery(OuterRef需要子查询),我们可以使用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是一个聚合函数。现在它不会影响结果,但是在其他情况下可能会影响结果。这就是docs建议采用不同方法的原因,其中聚合是通过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"
    

    Python:检查是否存在维基百科文章 - python

    我试图弄清楚如何检查Wikipedia文章是否存在。例如,https://en.wikipedia.org/wiki/Food 存在,但是https://en.wikipedia.org/wiki/Fod 不会,页面只是说:“维基百科没有此名称的文章。”谢谢! 参考方案 >>> import urllib >>> prin…

    Django-一个CBV可处理多种情况 - python

    我很难理解如何使用单个CBV处理(至少)2种不同情况。这是我想做的事情:我有一个ListView来显示对象列表。从那里,我生成一个链接以导航到DetailView以显示对象的详细信息。从那里,我生成一个链接到呈现相关报告的不同视图。我想使用以下网址:1. /myapp/list.html/ 2. /myapp/detail.html/<<uuid…

    Python Pandas导出数据 - python

    我正在使用python pandas处理一些数据。我已使用以下代码将数据导出到excel文件。writer = pd.ExcelWriter('Data.xlsx'); wrong_data.to_excel(writer,"Names which are wrong", index = False); writer.…

    Python uuid4,如何限制唯一字符的长度 - python

    在Python中,我正在使用uuid4()方法创建唯一的字符集。但是我找不到将其限制为10或8个字符的方法。有什么办法吗?uuid4()ffc69c1b-9d87-4c19-8dac-c09ca857e3fc谢谢。 参考方案 尝试:x = uuid4() str(x)[:8] 输出:"ffc69c1b" Is there a way to…

    Python-如何检查Redis服务器是否可用 - python

    我正在开发用于访问Redis Server的Python服务(类)。我想知道如何检查Redis Server是否正在运行。而且如果某种原因我无法连接到它。这是我的代码的一部分import redis rs = redis.Redis("localhost") print rs 它打印以下内容<redis.client.Redis o…