在 Django 中过滤嵌套的相关对象

我与 3 个模型的关系相当简单,并且在构建以我需要的方式返回结果的查询集时遇到问题。


楷模:



class Book(models.Model):

    name = models.CharField()


class CategoryLabel(models.Model):

    name = models.CharField()


class Review(models.Model):

    user = models.ForeignKey(User)

    book = models.ForeignKey(Book)

    labels = models.ManyToManyField(CategoryLabel)

    rating = models.IntegerField()


现在,查询集的结果应该是特定用户写过评论的书籍列表。


这很容易实现 books = Book.objects.filter(review__user=user)


棘手的部分是我需要输出(通过 django rest 框架序列化程序)一个书籍列表,每个书籍包含一个仅针对指定用户的评论列表、聚合平均评分(同样,仅针对指定用户)和一组评论被标记的不同标签。


所以在 JSON 中是这样的:


[

    "name": "Book1",

    "reviews": [

        "review_id1", "review_id2"

    ],

    "average_rating": 3,

    "labels": [

        "label_id1", "label_id2"

    ]

]

到目前为止我尝试过的:


Book.objects.filter(reviews__user=user)

            .annotate(average_rating=Avg("reviews__rating"))

            .annotate(labels=ArrayAgg("reviews__labels", distinct=True))

任何想法如何尽可能有效地实现这一目标?数据库是 PostgreSQL,因此 pg 特定功能是一个选项。


ABOUTYOU
浏览 140回答 2
2回答

翻翻过去那场雪

愚蠢,但原始问题中的代码确实有效。我遇到的问题在其他地方,与此示例无关...:/原始问题中有一个不正确的陈述:This does produce the format I need but it aggregates average rating over all reviews, not only the ones by the user and the same story with labels, it just includes all labels applied in all reviews...实际上并非如此,因此这似乎可以正常工作:Book.objects.filter(reviews__user=user)            .annotate(average_rating=Avg("reviews__rating"))            .annotate(labels=ArrayAgg("reviews__labels", distinct=True))

倚天杖

根据您的模型和您的问题描述,听起来您希望通过对特定用户过滤评论的书籍对评论进行分组:Review.objects.filter(user=user).values('book__name').annotate(&nbsp; &nbsp; average_rating=Avg(F('rating')))>>> <QuerySet [{'book__name': 'The ultimate code', 'average_rating': 7.0}]>抱歉,我没有使用 ArrayAgg 进行测试,它是 postgresSQL 特定的聚合函数。上面的代码是针对包含 2 个评论的数据库执行的,一个评分为 10,另一个评分为 4。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python