简体   繁体   English

在 Django 中对列表列表的元素进行排名和计数

[英]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.对于简单的多对多关系,模型将有两个字段/列,在您的情况下, usergenre ,每个类似用户的对有一个实例/行。

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.

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