Reputation: 6058
I've the following models
class Article(models.Model):
title = models.CharField(max_length=255, db_index=True)
slug = UniqueSlugField(prepopulate_from='title', unique=True)
favorited = models.ManyToManyField(to=User, blank=True)
tags = TaggableManager()
...
class Vote(models.Model):
article = models.ForeignKey(to=Article)
voter = models.ForeignKey(to=User, related_name='voter')
timestamp = models.DateTimeField(auto_now_add=True)
...
I use following line of code to get popular articles in descending order for a selected tag
Vote.objects.filter(tags__in=[tag]).annotate(num_articles=Count('article')).order_by('-num_articles')
How to build orm query to get popular articles by the following field of Article.favorited
and based on Vote
model?
Thanks,
Sultan
Upvotes: 0
Views: 1585
Reputation: 23871
Use join
Article.objects.filter(favorited__in=[...]).annotate(
vc=models.Count('vote')).order_by('-vc')
Or normally faster(less joins), but more complex, and limited(no longer a QuerySet but not a big issue normally) sub-query version
qs = Article.objects.filter(favorited__in=[...])
top_votes = Vote.objects.filter(article__in=qs).values('article').annotate(
vc=models.Count('pk')).values_list('article', 'vc').order_by('-vc')
# normally you may only want Top N
top_n_pks = tuple(pk for pk, vc in top_votes[:N])
tops = sorted(Article.objects.filter(pk__in=top_n_pks).order_by(),
key=lambda x: top_n_pks.index(x.pk))
Upvotes: 0
Reputation: 239290
Why would you get "popular articles" through the Vote
model? When you run the query, you end up with a queryset of Vote
s. Then, you must issue additional queries to get the Article
s from that.
You should be using:
Article.objects.filter(tags=tag).annotate(vote_count=Count('vote')).order_by('-vote_count')
Then, you have a proper queryset of Article
s and you're good to go.
If you want favorites, you would modify the above to use user
instead of vote
:
Article.objects.filter(tags=tag).annotate(favorite_count=Count('user')).order_by('-favorite_count')
Upvotes: 3