使用反向关系的第一行中的列来注释Django查询集

时间:2016-05-25 09:43:06

标签: python django django-orm

我有一个Review模型,并且有一个ReviewScore ForeignKey,表示某个时间点的分数。简化,它看起来像这样:

class Review(models.Model):
    # Nothing interesting here.


class ReviewScore(models.Model):
    review = models.ForeignKey(Review)
    date = models.DateField()
    score = models.IntegerField()

    class Meta:
        ordering = ("-date",)

在我看来,我希望使用ReviewScore表中最新一行的score值注释一个Review查询集(具体来说,我想要平均值),这样我就可以根据评论的最新分数进行排序。

我已经尝试了.annotate(score=F("reviewscore__score")),但这会返回多行;因此它返回重复Review个,每个都使用不同的ReviewScore分数进行注释,并且使用distinct无法解决此问题,因为Postgres要求distinct必须与ORDER BY表达式匹配。

这可能吗?我可以以某种方式过滤或限制使用.annotate返回外表的结果,或者只使用ReviewScore表中的第一个结果进行注释吗?

2 个答案:

答案 0 :(得分:1)

以下内容应使用您所指的Postgres功能(distinct(*fields)):

Review.objects
    .annotate(score=F("reviewscore__score"), date=F("reviewscore__date"))
    .order_by('pk', '-date')  # groups by id and descending date
    .distinct('pk')

如果你想要一个不同于pk的显示顺序,我认为你必须在Python中排序,因为任何带有pk__in的嵌套过滤器都会丢失注释。

答案 1 :(得分:1)

在最新的Django版本中,您可以在注释中使用Subquery expressions

from django.db.models import OuterRef, Subquery

scores = ReviewScore.objects.filter(review=OuterRef("pk")).order_by("-date")
reviews = Review.objects.annotate(
    latest_score=Subquery(scores.values("score")[:1])
)
sorted_reviews = reviews.order_by('latest_score')

这样,您可以与数据库无关(例如,与sqlite3一起使用)。

相关问题