Элементы ранга и подсчета списков в django - PullRequest
1 голос
/ 18 февраля 2020

У меня есть модели 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'}]

Есть ли запрос или другой метод для эффективного получения требуемого ранжирования?

Ответы [ 2 ]

1 голос
/ 19 февраля 2020

Поля ManyToMany в Django поддерживаются актуальными моделями (и, следовательно, таблицами).

Вы можете получить модель поддержки с помощью .through:

GenreLikes = User.liked_genres.through

Для простого отношение «многие ко многим», модель будет иметь два поля / столбца, user и genre в вашем случае, один экземпляр / строку на пользовательскую пару.

Таким образом, вы должны иметь возможность чтобы получить свой рейтинг с помощью

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

или аналогичного.

1 голос
/ 18 февраля 2020

Попробуйте это

from django.db.models import Count
Genre.objects.annotate(likes=Count('user')).order_by('-likes')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...