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

问题描述 投票:0回答:4

考虑这个查询:

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

实际上我需要的是用最新的

Novel
对象来注释每个
Chapter
,所以在这个查询之后,我必须执行另一个查询来通过注释的 ID 选择实际对象。海事组织这很丑陋。有没有办法将它们组合成一个查询?

python django django-orm annotate
4个回答
32
投票

是的,这是可能的。

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

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 上测试。


15
投票

Django 3.2+ 可以实现

利用

django.db.models.functions.JSONObject
(在 Django 3.2 中添加)来组合多个字段(在本例中,我正在获取最新的对象,但是可以获取任何任意对象,前提是您可以获得
LIMIT 1)
来生成您的对象):

MainModel.objects.annotate(
    last_object=RelatedModel.objects.filter(mainmodel=OuterRef("pk"))
    .order_by("-date_created")
    .values(
        data=JSONObject(
            id="id", body="body", date_created="date_created"
        )
    )[:1]
)

5
投票

是的,使用子查询

from django.db.models import OuterRef, Subquery

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 上测试

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

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

希望这对那些像我一样晚来的人有帮助。


4
投票

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

您可以阅读以下博客文章找到两种解决方法。

© www.soinside.com 2019 - 2024. All rights reserved.