【问题标题】:Django's NotImplementedError: aggregate() + distinct(fields) not implementedDjango 的 NotImplementedError:聚合()+不同(字段)未实现
【发布时间】:2019-04-23 15:25:55
【问题描述】:

我有非常简单的模型:

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 的评分,我需要检索所有最新 用户反馈并总结所有评分值。以下是检索每个用户的所有最后反馈的代码:

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

请帮我解决这个问题:)

【问题讨论】:

标签: python django postgresql


【解决方案1】:

看来你需要这个或类似的东西:

place.feedback_set.values('profile').annotate(rating_sum=Sum(rating)).values('profile','rating_sum').order_by('profile')

【讨论】:

  • 感谢您的回复。但我认为你错过了一件事情:我需要接受每个用户的最后评分。
【解决方案2】:

我猜你正在寻找这样的聚合数据:

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 评论后:

我需要计算给定地点的平均评分,并仅过滤个人资料留下的最后评分。

您正在寻找django window functions 中的FirstValue

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"

【讨论】:

  • 这肯定会失败。首先,您过滤Profile 对象。但我需要计算给定地点的平均评分,并仅过滤个人资料留下的最后评分。
  • 是我的错。在冒险回答之前寻求更多解释是一种方式。 “个人资料只剩下最后一个评分”不是您的问题。
  • 我也不好。强调有问题的相关词。谢谢
  • 我误解了“我需要检索所有LAST用户反馈并总结所有”。现在我明白了,它的意思是:“我需要为每个用户检索 LASTEST 反馈并总结所有”“所有最后用户反馈”“最新反馈” 不同。我的英语有问题,srr。 :(
  • 我发布了答案。用 django 2.2.0 编写。
猜你喜欢
  • 2021-10-21
  • 2021-01-20
  • 2016-11-29
  • 2010-12-20
  • 2018-09-30
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 2016-08-16
相关资源
最近更新 更多