在 django 中,有没有办法在单个查询中直接用相关对象注释查询?

Posted

技术标签:

【中文标题】在 django 中,有没有办法在单个查询中直接用相关对象注释查询?【英文标题】:In django, is there a way to directly annotate a query with a related object in single query? 【发布时间】:2012-08-21 12:56:35 【问题描述】:

考虑这个查询:

query = Novel.objects.< ...some filtering... >.annotate(
    latest_chapter_id=Max("volume__chapter__id")
)

实际上,我需要用最新的Chapter 对象注释每个Novel,因此在此查询之后,我必须执行另一个查询以通过注释ID 选择实际对象。 IMO 这很丑陋。有没有办法将它们组合成一个查询?

【问题讨论】:

你能用小说来注释章节吗? 对我来说似乎不可能,因为我只需要每部小说的最新章节,但一部小说有很多章节,而且章节的卷数不同。据我所知,distinct() 在这种情况下是没有用的(如果我错了,请纠正我),除了从小说开始外,我不知道有任何其他方法可以准确地选择一章。有什么想法吗? 【参考方案1】:

是的,这是可能的。

要获得一个查询集,其中包含小说中最后一个章节的所有章节,只需执行以下操作:

from django.db.models.expressions import F
from django.db.models.aggregates import Max

Chapters.objects.annotate(last_chapter_pk=Max('novel__chapter__pk')
    ).filter(pk=F('last_chapter_pk'))

在 Django 1.7 上测试。

【讨论】:

【参考方案2】:

不,不可能将它们组合成一个查询。

您可以阅读以下blog post 以找到两种解决方法。

【讨论】:

rune-kaagaard 的答案现在更好了。 链接的帖子建议在查询中使用 extra() 。从 Django 1.8 开始,不推荐使用 extra() 并将其弃用。【参考方案3】:

是的,使用子查询,文档:https://docs.djangoproject.com/en/3.0/ref/models/expressions/#subquery-expressions

latest_chapters = Chapter.objects.filter(novel = OuterRef("pk"))\
    .order_by("chapter_order")

novels_with_chapter = Novel.objects.annotate(
    latest_chapter = Subquery(latest_chapters.values("chapter")[:1]))

在 Django 3.0 上测试

子查询在小说的选择语句中创建一个选择语句,然后将其添加为注释。这意味着您只需访问数据库一次。

我也更喜欢 Rune 的答案,因为它实际上注释了一个 Novel 对象。

希望这对任何像我一样晚来的人都有帮助。

【讨论】:

不幸的是对我不起作用,因为子查询似乎只能返回一列而不是完整的对象。 @Gnietschow,是的,如果您想要的不仅仅是一列,您最好使用类似 prefetch_related docs 不幸的是,这对我不起作用,因为我想对两个模型的字段进行排序和过滤。

以上是关于在 django 中,有没有办法在单个查询中直接用相关对象注释查询?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在单个 mysql 查询中搜索所有字段? [复制]

当查询被填充时,有没有办法在 Django 模板中呈现大型查询集?

有没有办法在单个 psql 查询中返回总计数和行数?

有没有办法用非表达式注释 django 查询?

Django:有没有办法从单元测试中计算 SQL 查询?

SQLAlchemy 单个查询从两个表中返回列