Django通过谓词和计数结果注释查询集
Posted
技术标签:
【中文标题】Django通过谓词和计数结果注释查询集【英文标题】:Django annotate queryset by predicate and count results 【发布时间】:2022-01-10 05:18:51 【问题描述】:我有两个模型:
class Game(models.Model):
id = models.AutoField(primary_key=True)
class Score(models.Model):
id = models.AutoField(primary_key=True)
game = models.ForeignKey(Game, related_name="score", on_delete=models.CASCADE)
first_score = models.IntegerField(blank=True)
second_score = models.IntegerField(blank=True)
is_rusk = models.BooleanField(blank=True)
我得到了一个游戏对象的查询集:
[
"id": 314317035,
"score": [
"first_score": 5,
"second_score": 1,
"is_rusk": false
]
,
"id": 311298177,
"score": [
"first_score": 5,
"second_score": 2,
"is_rusk": false
]
,
"id": 310278749,
"score": [
"first_score": 5,
"second_score": 2,
"is_rusk": false
]
,
"id": 309866238,
"score": [
"first_score": 5,
"second_score": 0,
"is_rusk": true
]
,
"id": 307926664,
"score": [
"first_score": 5,
"second_score": 0,
"is_rusk": true
]
,
"id": 306047964,
"score": [
"first_score": 4,
"second_score": 5,
"is_rusk": false
]
,
"id": 304881611,
"score": [
"first_score": 5,
"second_score": 3,
"is_rusk": false
]
,
"id": 304468136,
"score": [
"first_score": 5,
"second_score": 2,
"is_rusk": false
]
,
]
我想用rusks_cnt
注释这个查询集,它将计算带有is_rusk=True
的对象,如果有办法不将它添加到每个对象,就像一个字段一样,那也很好。
我认为最简单的方法是:
cnt = queryset.filter(score__is_rusk=True).count()
但是当我尝试这样注释时:
cnt = queryset.filter(score__is_rusk=True).count()
queryset = queryset.annotate(cnt=cnt)
上面写着:
QuerySet.annotate() received non-expression(s): 2.
我也试过了:
queryset = queryset.annotate(
rusk_cnt=Sum(
Case(When(score__is_rusk=True, then=1)), output_field=IntegerField()
)
)
但结果是:
[
"id": 279658929,
"rusk_cnt": 1
,
"id": 279796553,
"rusk_cnt": null
,
...
]
我还想知道只是使用.count()
会导致性能不佳吗?
【问题讨论】:
【参考方案1】:您可以使用Value
进行注释:
from django.db.models import Value
cnt = queryset.filter(score__is_rusk=True).count()
queryset = queryset.annotate(cnt=Value(cnt))
但这将添加 same 值:Game
s 中的Score
对象的数量queryset
到所有 Game
对象,这没有多大意义。
如果您想用True
注释Game
对象的数量Score
和is_rusk=True
,您可以使用:
from django.db.models import Q, Sum
queryset.annotate(
rusk_cnt=Sum('score', filter=Q(score__is_rusk=True))
)
【讨论】:
【参考方案2】:注释用于对每个条目进行计算。如果要计算整个查询集,请使用聚合。
Difference between Django's annotate and aggregate methods?
【讨论】:
以上是关于Django通过谓词和计数结果注释查询集的主要内容,如果未能解决你的问题,请参考以下文章