Django的NotImplementedError:aggregate()+ distinct(fields)未实现

时间:2019-04-23 15:25:56

标签: python django postgresql

我有非常简单的模型:

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作为数据库。

请帮助我解决这个问题:)

2 个答案:

答案 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')