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.
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 forannotate_pool
, resulting in duplicateProtostic
s that are only differentiated by the relatedBet
fields, which again leads to a lower bet count. Test:True
orFalse
? My guess isTrue
(provided thatannotate_pool
is unfiltered and contains allPronostic
objects). This means that you have duplicatePronostic
s inannotate_pool
. The number ofBet
s is spread out over those duplicates.Based on the SQL you posted, your
Pronostic
objects are ordered by the fielddate
in a relatedMatch
object. If you remove the ordering (using an emptyorder_by()
), I would expect the numbers to match up. Test this: