简体   繁体   中英

Django count with group in annotation

I have a profile model with a ManyToMany field called that relates to a Stock . In my admin dashboard I'm trying to show the number of watchlists each stock is in. The annotation query I have is:

qs.annotate(watchlist_count=Count('profile__watchlist__symbol'))

But it's returning incorrect results

Here are the models:

class Profile(models.Model):
    user = OneToOneField(User, on_delete=models.CASCADE)
    watchlist = ManyToManyField(Stock, blank=True)

    def __str__(self):
        return self.user.email


class Stock(models.Model):
    symbol = CharField(max_length=15, unique=True)
    name = CharField(max_length=100)
    category = CharField(max_length=30, choices=CATEGORY_CHOICES, blank=True)
    about = TextField(help_text='About this company')

    def __str__(self):
        return f'{self.symbol} - {self.name}'

The equivalent SQL query is:

select stock_id, count(stock_id) from api_profile_watchlist group by stock_id;

What is wrong with my annotation query?

You do too much joins. By joining twice over the many-to-many relation, you "blow up" the count.

You can simply count the amount of watchlists with that Stock , with:

from django.db.models import Count

Stock.objects.annotate(
    
)

This works since, by default, the related_query_name=… [Django-doc] has the name of the model (or the related_name if you specified one). So the implicit relation you wrote from Stock to Profile (the reverse one of Profile to Stock in your watchlist relation), is profile (in lowercase). We thus ask Django to count, for a given Stock object, the number of relations to a Profile .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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