[英]Rank and count elements of list of lists in django
I have a Genre
and a User
models.我有一个
Genre
和一个User
模型。 Each Genre
has an id
and a name
, and there is a many-to-many relationship, so that each User
likes 0 or more Genres
.每个
Genre
都有一个id
和一个name
,并且存在多对多关系,因此每个User
喜欢 0 个或多个Genres
。
Is there an efficient query for obtaining how many likes has each Genre, across all users, in descendant order?是否有一个有效的查询来获取每个流派在所有用户中按后代顺序有多少喜欢?
My current approach works, but it is extremely inefficient since it has to read all the likes of all the users for each genre:我目前的方法有效,但效率极低,因为它必须读取每种类型的所有用户的所有喜好:
In [1]: genres = list(Genre.objects.values('name', 'id'))
In[2]: genres
Out[2]:
[{'id': 10, 'name': 'Rock'},
{'id': 11, 'name': 'Pop'},
{'id': 12, 'name': 'Hip hop'},
{'id': 13, 'name': 'Electronic'},
{'id': 14, 'name': 'Classical'}]
In [3]: likes_by_users = []
In [4]: users = list(User.objects.all())
In [5]: for u in users:
...: current_user_likes = []
...: likes_by_users.append(current_user_likes)
...: for lg in u.liked_genres.all():
...: current_user_likes.append(lg.pk)
In [6]: likes_by_users
Out[6]:
[[14],
[11, 12],
[11, 10, 13, 12],
[],
[13, 12, 10, 1
[10, 11]]
In [7]: counts = {}
In [8]: for g in genres:
...: counts[g['id']] = {
...: 'name' : g['name'],
...: 'likes': 0
...: }
...: for l in likes_by_users:
...: for gid in l:
...: if gid == g['id']:
...: counts[gid]['likes'] += 1
In [9]: ranking = sorted(list(counts.values()), key=lambda x : x['likes'], reverse=True)
And this is exactly the output that I need:这正是我需要的输出:
In [9]: ranking
Out[9]:
[{'likes': 4, 'name': 'Pop'},
{'likes': 3, 'name': 'Rock'},
{'likes': 3, 'name': 'Hip hop'},
{'likes': 2, 'name': 'Electronic'},
{'likes': 1, 'name': 'Classical'}]
Is there a query or another method for obtaining in an efficient way the required ranking?是否有查询或其他方法可以有效地获得所需的排名?
Try this尝试这个
from django.db.models import Count
Genre.objects.annotate(likes=Count('user')).order_by('-likes')
ManyToMany fields in Django are backed by actual models (and thus tables). Django 中的 ManyToMany 字段由实际模型(以及表格)支持。
You can get at the backing model via .through
:您可以通过
.through
获得支持模型:
GenreLikes = User.liked_genres.through
For a simple many-to-many relation, the model will have two fields/columns, user
and genre
in in your case, one instance/row per user-like pair.对于简单的多对多关系,模型将有两个字段/列,在您的情况下,
user
和genre
,每个类似用户的对有一个实例/行。
Thus, you should be able to get your ranking with just因此,您应该能够获得您的排名
GenreLikes.objects.values('genre').annotate(likes=Count('user')).order_by('-likes')
or similar.或类似。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.