Django Aggregation Count

北战南征 提交于 2019-12-10 16:36:17

问题


I'm trying to filter my model with an aggregate function.

I have a Model A and a Model B with a foreign key on the model A.

annotate_pool = queryset.annotate(nb_bets=Count('bets')).all()
for obj in annotate_pool:
    bets_obj = obj.bets.all()
    bets_length = len(bets_obj)
    print(obj.nb_bets, bets_length)

And the annotation doesn't give me the same result as the function length.

1 1
1 2
1 2
1 2
1 2
1 1
1 1
2 2

Here is my models:

class Pronostic(models.Model):
    cote_total = models.FloatField(default=0.0)
    trust = models.IntegerField()
    mise_ratio = models.IntegerField(default=10)
    safe = models.BooleanField(default=False)

class Bet(models.Model):
    name = models.CharField(max_length=255)
    match = models.ForeignKey('pronostics.Match', on_delete=models.CASCADE, related_name='bets')
    cote = models.FloatField()
    status = models.IntegerField(choices=STATUS, default=0)
    pronostic = models.ForeignKey('pronostics.Pronostic', related_name='bets', on_delete=models.CASCADE)

len(bets_obj) should give me the same result as Count('bets'). What is going on? Why does Count give me a wrong result?

Thank you in advance.

EDIT:

I'm using django-rest-framework, and try to add a custom filter. (see doc here). The result expected is: obj.nb_bets should be equal to bets_length. Since I want to filter my models like this:

queryset.annotate(nb_bets=Count('bets')).filter(nb_bets__gte=2)

or

queryset.annotate(nb_bets=Count('bets')).filter(nb_bets__lte=2)

Here is the SQL query contained in my queryset:

SELECT "pronostics_pronostic"."id",
       "pronostics_pronostic"."cote_total",
       "pronostics_pronostic"."trust",
       "pronostics_pronostic"."mise_ratio",
       "pronostics_pronostic"."safe"
FROM "pronostics_pronostic"
LEFT OUTER JOIN "pronostics_bet" 
       ON ("pronostics_pronostic"."id" = "pronostics_bet"."pronostic_id")
LEFT OUTER JOIN "pronostics_match" 
       ON ("pronostics_bet"."match_id" = "pronostics_match"."id")
WHERE ("pronostics_pronostic"."visible" = TRUE
       AND "pronostics_pronostic"."safe" = TRUE)
ORDER BY "pronostics_match"."date" DESC

If you need more information, let me know.


回答1:


Based on the SQL you posted, your Pronostic objects are ordered by the field date in a related Match object. If you remove the ordering (using an empty order_by()), I would expect the numbers to match up. Test this:

annotate_pool = queryset.order_by().annotate(nb_bets=Count('bets')).all()



回答2:


This is a trick question as long as you don't show the queryset for annotate_pool.

My guess is that you have fields from Bet in your SQL query for annotate_pool, resulting in duplicate Protostics that are only differentiated by the related Bet fields, which again leads to a lower bet count. Test:

Pronostic.objects.count() < len(annotate_pool)

True or False? My guess is True (provided that annotate_pool is unfiltered and contains all Pronostic objects). This means that you have duplicate Pronostics in annotate_pool. The number of Bets is spread out over those duplicates.



来源:https://stackoverflow.com/questions/55156661/django-aggregation-count

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!