Python django中列表列表的排序和计数元素

Python django中列表列表的排序和计数元素,python,django,python-3.x,django-models,django-queryset,Python,Django,Python 3.x,Django Models,Django Queryset,我有类型和用户模型。每个类型都有一个id和一个名称,并且存在多对多关系,因此每个用户喜欢0个或多个类型 是否有一个有效的查询来获取所有用户对每种体裁的喜爱程度,并按后代顺序排列? 我目前的方法可行,但效率极低,因为它必须阅读所有用户对每种类型的喜好: In [1]: genres = list(Genre.objects.values('name', 'id')) In[2]: genres Out[2]: [{'id': 10, 'name': 'Rock'}, {'id': 11, '

我有
类型
用户
模型。每个
类型
都有一个
id
和一个
名称
,并且存在多对多关系,因此每个
用户
喜欢0个或多个
类型

是否有一个有效的查询来获取所有用户对每种体裁的喜爱程度,并按后代顺序排列?

我目前的方法可行,但效率极低,因为它必须阅读所有用户对每种类型的喜好:

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中的许多字段都有实际模型(以及表)支持

您可以通过
获取支持模型。通过

GenreLikes = User.liked_genres.through
对于简单的多对多关系,该模型将有两个字段/列,
user
genre
,在您的情况下,每个类用户对一个实例/行

因此,你应该能够得到你的排名与公正

GenreLikes.objects.values('genre').annotate(likes=Count('user')).order_by('-likes')

这是文档中的一个示例:
Entry.objects.filter(pub\u date\u year=2005)。order\u by('-pub\u date',headline')
annotate
可以直接在
querystmanager
上调用,而无需将其链接到
all
谢谢您的回答。由于这是一种多对多关系,因此没有
user
属性,而是
属性。调用
Genre.objects.all().annotate(likes=Count('liked_by'))
时,它只列出所有类型。调用
Genre.objects.all().annotate(likes=Count('liked_by')).order_by('-likes')
时,它会返回一个包含大量重复条目的庞大流派列表,因此我认为每个条目都代表了用户对某个流派的喜好。有没有办法修复此查询,使结果类似于我的问题中的
排名
列表?@SusyP你能将你的
用户
(如果不是默认值)和
类型
模型添加到问题中吗?@SusyP在我的测试应用程序上,我的决定很好,没有重复条目,不确定你的情况下出了什么问题。谢谢。这种方法很有效,但我必须添加
'user'
作为
Count()
的参数。如果您能纠正这一点,我将不胜感激。@SusyP完成交易。:)