我有两种型号:
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()
会导致糟糕的性能吗?
注释用于计算每个条目。如果要计算整个查询集,请使用"聚合"。
Django';s注释和聚合方法?
您可以使用Value
:进行注释
from django.db.models importValue
cnt = queryset.filter(score__is_rusk=True).count()
queryset = queryset.annotate(cnt=Value(cnt))
但这将添加相同的值:queryset
中Game
的Score
对象数到所有Game
对象数,这没有多大意义。
如果您想用True
注释Game
对象——其中Score
和is_rusk=True
的对象数量,您可以使用:
from django.db.models importQ, Sum
queryset.annotate(
rusk_cnt=Sum('score', filter=Q(score__is_rusk=True))
)