【问题标题】:Rank and count elements of list of lists in djangodjango中列表列表的排名和计数元素
【发布时间】:2020-06-02 19:59:05
【问题描述】:

我有一个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'}]

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

【问题讨论】:

标签: python django python-3.x django-models django-queryset


【解决方案1】:

试试这个

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

【讨论】:

  • annotate 可以直接在QuerySetManager 上调用,而无需将其链接到all
  • 感谢您的回答。由于这是多对多关系,因此没有 user 属性,而是 liked_by 属性。当调用Genre.objects.all().annotate(likes=Count('liked_by')) 时,它只会列出所有类型。当调用Genre.objects.all().annotate(likes=Count('liked_by')).order_by('-likes') 时,它会返回一个包含大量重复条目的庞大流派列表,所以我认为每个条目都代表了用户喜欢的流派。有没有办法修复这个查询,使结果类似于我的问题中的ranking 列表?
  • @SusyP 你可以添加你的User(如果不是默认)和Genre 模型来提问吗?
  • @SusyP 在我的测试应用程序上,我的决定运行良好,没有重复条目,不确定您的情况出了什么问题。
【解决方案2】:

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

您可以通过.through获取支持模型:

GenreLikes = User.liked_genres.through

对于简单的多对多关系,模型将有两个字段/列,usergenre 在您的情况下,每个类似用户对一个实例/行。

因此,您应该能够获得您的排名

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

或类似的。

【讨论】:

  • 谢谢。这种方法有效,但我必须添加'user' 作为Count() 的参数。如果您能纠正,我将不胜感激。
  • @SusyP 完成交易。 :)
猜你喜欢
  • 1970-01-01
  • 2014-04-09
  • 2013-12-02
  • 2022-12-18
  • 1970-01-01
  • 1970-01-01
  • 2021-09-06
  • 2018-05-08
  • 2012-02-07
相关资源
最近更新 更多