【问题标题】:Annotating Django querysets with a column from the first row of a reverse relation使用反向关系第一行中的列注释 Django 查询集
【发布时间】:2016-09-22 20:01:28
【问题描述】:

我有一个Review 模型和一个ReviewScore ForeignKey'd,代表某个时间点的分数。简化后如下所示:

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")) 但这会返回多行;因此它返回重复的Reviews,每个都用不同的ReviewScore 分数注释,并且使用distinct 无法解决这个问题,因为Postgres 要求distinct 必须匹配ORDER BY 表达式。

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

【问题讨论】:

    标签: python django django-orm


    【解决方案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)。

    【讨论】:

      【解决方案2】:

      以下内容应使用您所指的 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 的嵌套过滤器都会丢失注释。

      【讨论】:

        猜你喜欢
        • 2011-03-23
        • 2010-11-03
        • 2014-07-01
        • 2020-08-18
        • 2019-12-30
        • 2020-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多