简体   繁体   English

Django 通过谓词和计数结果注释查询集

[英]Django annotate queryset by predicate and count results

I have two models:我有两个模型:

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)

And I got a queryset of Game objects:我得到了一个游戏对象的查询集:

[
    {
        "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
            }
        ]
    },
]

I want to annotate this queryset with rusks_cnt , it will be count of objects with is_rusk=True , If there is a way to not add this to every object, just as one field, that would be good too.我想用rusks_cnt注释这个查询集,它将是带有is_rusk=True的对象的计数,如果有办法不将它添加到每个 object 中,就像一个字段一样,那也很好。

I think easiest way to do it like this:我认为最简单的方法是这样的:

cnt = queryset.filter(score__is_rusk=True).count()

But when I'm trying to annotate like this:但是当我试图这样注释时:

cnt = queryset.filter(score__is_rusk=True).count()
queryset = queryset.annotate(cnt=cnt)

It says:它说:

QuerySet.annotate() received non-expression(s): 2.

I've also tried:我也试过:

queryset = queryset.annotate(
         rusk_cnt=Sum(
                Case(When(score__is_rusk=True, then=1)), output_field=IntegerField()
            )
        )

But results are:但结果是:

[
    {
        "id": 279658929,
        "rusk_cnt": 1
    },
    {
        "id": 279796553,
        "rusk_cnt": null
    },
    ...
]

Also I wondering is just using .count() will lead to bad performance?另外我想知道只是使用.count()会导致性能不佳吗?

You can annotate with a Value :您可以使用Value进行注释:

from django.db.models import Value

cnt = queryset.filter(score__is_rusk=True).count()
queryset = queryset.annotate(cnt=Value(cnt))

But this will add the same value: the number of Score objects for the Game s in the queryset to all Game objects, which does not make much sense.但这将添加相同的值:查询集中GameScore对象的queryset所有Game对象,这没有多大意义。

If you want to annotate the Game objects with True the number of objects where Score with is_rusk=True , you can work with:如果您想用True注释Game对象,使用is_rusk=True Score的对象数量,您可以使用:

from django.db.models import Q, Sum

queryset.annotate(
    rusk_cnt=Sum('score', filter=Q(score__is_rusk=True))
)

Annotate is for calculating on every entry. Annotate 用于计算每个条目。 If you want to calculate for the entire queryset, use Aggregate.如果要计算整个查询集,请使用聚合。

Difference between Django's annotate and aggregate methods? Django的注释和聚合方法之间的区别?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM