Django 上 Count 函数的不同行为

Posted

技术标签:

【中文标题】Django 上 Count 函数的不同行为【英文标题】:Different behaviour of Count function on Django 【发布时间】:2021-08-17 03:59:32 【问题描述】: 我有一个非常奇怪的情况,如果将 Count() 应用于通过 id 或其他过滤器过滤的模型,它的行为会有所不同。 我有这些模型:
class Segment(models.Model):
    is_completed = models.BooleanField(default=False)

class Waypoint(models.Model):
    is_visited = models.BooleanField("is visited", default=False)
    segment = models.ForeignKey("Segment", on_delete=models.PROTECT, related_name="waypoints", null=True, default=None)

假设我们有两个尚未访问过的航路点,都与同一航段相关。 我在查询集中有这些航点之一,称之为wp。现在,如果我执行:

to_visit_filter = Q(waypoints__is_visited=False)
seg = Segment.objects.filter(waypoints__in=wp, is_completed=False).annotate(
            wp_to_visit=Count('waypoints', filter=to_visit_filter))

print(seg.first().wp_to_visit)   // 1

相反,如果我这样做:

to_visit_filter = Q(waypoints__is_visited=False)
segm_id = [w.segment.id for w in wp]
seg = Segment.objects.filter(id__in=segm_id, is_completed=False).annotate(
            wp_to_visit=Count('waypoints', filter=to_visit_filter))

print(seg.first().wp_to_visit)   // 2

在这两种情况下seg.first() 都给出了相同的对象实例,但是要访问的路点数量不同。为什么?

【问题讨论】:

【参考方案1】:

在您的第一个查询中,您对 航点 (waypoints__in=wp) 执行过滤,因此将航点限制为选定的Waypoint。此过滤导致带有Waypoint 模型和WHERE 子句的LEFT OUTER JOIN。接下来,您使用waypoints 上的Count 对航路点执行聚合和分组。此注释将使用与上一次调用 filter 相同的连接,因此显然您的计数结果为 1。

接下来在您的第二个查询中,您不是过滤航点,而是过滤段 @​​987654327@ 本身,因此没有对航点进行过滤,您的查询为您提供 2 的计数。

【讨论】:

以上是关于Django 上 Count 函数的不同行为的主要内容,如果未能解决你的问题,请参考以下文章

在过滤损坏的记录字段时,Spark 的 .count() 函数与数据帧的内容不同

Django - 如何注释不同值的 count()

Oracle 上 SELECT * 和 SELECT COUNT(*) 之间的结果大小不同

django-filter + DRF ModelView为不同的字段设置不同的行为

带有 django-nose 的 Django:两个相同的设置文件,在运行测试命令时具有不同的行为

在 Windows 或 Linux 上运行时函数的行为不同