django - Django 上 Count 函数的不同行为
问题描述
我有一个非常奇怪的情况,如果将 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()
给出相同的对象实例,但要访问的路点数不同。为什么?
解决方案
In your first query you perform filtering on the waypoints (waypoints__in=wp
) and hence have limited the waypoints to that one selected Waypoint
. This filtering results in a LEFT OUTER JOIN with the Waypoint
model and a WHERE clause. Next you perform aggregation and group by on waypoints by using Count
on waypoints
. This annotation would use the same join made by the previous call to filter
and hence obviously your count has the result of 1.
Next in your second query instead of filtering on waypoints, you filter on the segments id
itself, hence there is no filtering on the waypoints and your query gives you the count of 2.
推荐阅读
- android - Flutter - 使用带有 android 多种风格的 fastlane
- swift - Swift UI 细节移除
- seo - Favicon/图标未反映在谷歌搜索结果中
- android - UnitialisedPropertyAccessException 即使在初始化了 lateinit var 之后?
- xml - xQuery:在 TEI 中查找未注释的文本
- ios - Fastlane 与 Jenkins 的集成
- android - Xamarin android 项目未构建
- python - 如何使用 urllib2 模块 python2.7 处理此错误
- excel - 从 Excel 中的客户端应用程序导出 Firestore 数据
- java - 在 NativeScript 中使用 Android 原生代码 (JAVA)