我有非常简单的模型:
class Profile(models.Model):
name = models.CharField(max_length=100, unique=True)
age = models.IntegerField(default=18)
class Place(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
address = models.CharField(max_length=100, blank=True, null=True)
class ProfilePlaceFeedback(models.Model):
profile = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='feedback_set')
place = models.ForeignKey(Place, on_delete=models.CASCADE, related_name='feedback_set')
review = models.TextField(blank=True, null=True)
rating = models.IntegerField(default=0)
timestamp = models.DateTimeField(auto_now_add=True)
ProfilePlaceFeedback
-是用于存储用户剩余的每个评分的模型。
为了计算某些place
的评分,我需要检索所有 LATEST 用户反馈并汇总所有评分值。这是用于检索每个用户的所有最后反馈的代码:
place.feedback_set.order_by('profile', '-timestamp').distinct('profile')
但是要查询:
place.feedback_set.order_by('profile', '-timestamp').distinct('profile').aggregate(Sum(rating))
引发异常:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/PATH_TO_VIRTUALENV/lib/python3.6/site-packages/django/db/models/query.py", line 357, in aggregate
raise NotImplementedError("aggregate() + distinct(fields) not implemented.")
NotImplementedError: aggregate() + distinct(fields) not implemented.
使用Django 2.0和postgresql作为数据库。
请帮助我解决这个问题:)
答案 0 :(得分:0)
我想您正在寻找这样的汇总数据:
from django.db.models import F
Profile
.objects
.values(profile_name=F('name'),
place_name=F('profileplacefeedback__place__name'),
)
.annotate(timestamp=Max('profileplacefeedback__timestamp'),
rating=Sum('profileplacefeedback__rating'))
.order_by( 'profile_name', '-timestamp')
如果您需要更多数据,只需将其添加到values
部分。
免责声明:此处未测试查询,仅由手工编写。让我知道它是否无法解决或删除答案(以帮助将来的用户)
已编辑,在OP评论之后:
我需要计算给定位置的平均评分,并仅过滤个人资料剩余的最后评分。
您正在寻找FirstValue中的django window functions。
from django.db.models import Avg, F, RowRange, Window
from django.db.models.functions.window import FirstValue
q=( Place
.objects
.annotate(
avg_rating=Window(
expression=FirstValue('feedback_set__rating'),
partition_by=[F('feedback_set__profile'),
F('feedback_set__place')],
order_by=F('feedback_set__timestamp').desc()
)
)
.values(
place_name=F('feedback_set__place__name'),
)
.annotate(
rating=Avg('avg_rating')
)
)
基础SQL:
>>> print (q.query)
SELECT
T4."name" AS "place_name",
AVG(FIRST_VALUE("a_profileplacefeedback"."rating")
OVER (PARTITION BY "a_profileplacefeedback"."profile_id",
"a_profileplacefeedback"."place_id"
ORDER BY "a_profileplacefeedback"."timestamp" DESC)) AS "rating"
FROM
"a_place"
LEFT OUTER JOIN
"a_profileplacefeedback"
ON ("a_place"."id" = "a_profileplacefeedback"."place_id")
LEFT OUTER JOIN
"a_place" T4
ON ("a_profileplacefeedback"."place_id" = T4."id")
GROUP BY
T4."name"
答案 1 :(得分:0)
似乎您需要这个或类似的东西:
place.feedback_set.values('profile').annotate(rating_sum=Sum(rating)).values('profile','rating_sum').order_by('profile')