为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

ABOUTYOU 2021-10-26 10:22:12
我与 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 特定功能是一个选项。
查看完整描述

2 回答

?
翻翻过去那场雪

TA贡献2065条经验 获得超14个赞

愚蠢,但原始问题中的代码确实有效。我遇到的问题在其他地方,与此示例无关...:/


原始问题中有一个不正确的陈述:


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))


查看完整回答
反对 回复 2021-10-26
?
倚天杖

TA贡献1828条经验 获得超3个赞

根据您的模型和您的问题描述,听起来您希望通过对特定用户过滤评论的书籍对评论进行分组:


Review.objects.filter(user=user).values('book__name').annotate(

    average_rating=Avg(F('rating'))

)


>>> <QuerySet [{'book__name': 'The ultimate code', 'average_rating': 7.0}]>

抱歉,我没有使用 ArrayAgg 进行测试,它是 postgresSQL 特定的聚合函数。


上面的代码是针对包含 2 个评论的数据库执行的,一个评分为 10,另一个评分为 4。


查看完整回答
反对 回复 2021-10-26
  • 2 回答
  • 0 关注
  • 139 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信