Django: Получение среднего рейтинга для каждого пользователя
Как составить запрос, возвращающий список средних оценок пользователей в friendlist?
models.py
class Beer(models.Model):
id = models.BigIntegerField(primary_key=True)
name = models.CharField(max_length=150)
...
class Checkin(models.Model):
id = models.IntegerField(primary_key=True)
rating = models.FloatField(blank=True, null=True)
user = models.ForeignKey(User, on_delete=CASCADE)
...
class FriendList(models.Model):
user = models.OneToOneField(User, on_delete=CASCADE, primary_key=True)
friend = models.ManyToManyField(User, related_name="friends")
база данных (postgresql)
user | beer | rating |
---|---|---|
1 | 1 | 4.2 |
1 | 1 | 3.5 |
1 | 1 | 4.0 |
2 | 1 | 4.1 |
2 | 1 | 3.7 |
Мой текущий запрос, чтобы получить все регистрации друзей:
Checkin.objects.filter(beer=1, user__in=friends.friend.all())
Что дает мне что-то вроде:
[{user: 1, rating: 4.2}, {user: 1, rating: 3.5},...,{user: 2, rating: 4.1}...]
Что я хочу:
[{user: 1, avg_rating: 4.1}, {user: 2, avg_rating: 3.8}]
Более логично .annotate(…)
[Django-doc] объекты User
, так:
from django.db.models import Avg
friends.friend.filter(
checkin__beer_id=1
).annotate(
rating=Avg('checkin__rating')
)
Where checkin__
is the related_query_name=…
[Django-doc] for the user
from Checkin
to the User
model. If you did not specify a related_query_name=…
, then it will use the value for the related_name=…
[Django-doc], and if that one is not specified either, it will use the name of the source model in lowercase, so checkin
.
Объекты User
, возникающие из этого набора запросов, будут иметь дополнительный атрибут .rating
, содержащий среднее значение rating
над Checkin
s для данного beer_id
.
Note: It is normally better to make use of the
settings.AUTH_USER_MODEL
[Django-doc] to refer to the user model, than to use theUser
model [Django-doc] directly. For more information you can see the referencing theUser
model section of the documentation.