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

Rank and count elements of list of lists in django

我有一个 Genre 和一个 User 模型。每个Genre有一个id和一个name,是多对多的关系,这样每个User喜欢0个或多个Genres

是否有一个有效的查询来获取每个流派在所有用户中按后代顺序获得多少个赞?

我目前的方法可行,但效率极低,因为它必须读取每个类型的所有用户的所有赞:

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)

这正是我需要的输出:

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'}]

是否有查询或其他方法可以有效地获得所需的排名?

试试这个

from django.db.models import Count
Genre.objects.annotate(likes=Count('user')).order_by('-likes')

Django 中的 ManyToMany 字段由实际模型(以及表)支持。

您可以通过 .through:

获取支持模型
GenreLikes = User.liked_genres.through

对于简单的多对多关系,模型将有两个 fields/columns、usergenre,在您的情况下,每个用户一个 instance/row -喜欢一对。

因此,您应该可以通过

获得您的排名
GenreLikes.objects.values('genre').annotate(likes=Count('user')).order_by('-likes')

或类似。