Django原始查询 - 使用点表示法遍历相关模型字段

3 投票
2 回答
1419 浏览
提问于 2025-04-18 18:20

这是我在Django中的一个raw查询

q = Book.objects.raw('''
      SELECT * FROM 
        ( SELECT "book"."name", "author"."name", 
                 RANK() OVER (PARTITION BY "author"."id") AS "rank"
          FROM "book"
          INNER JOIN "book" ON ("book"."author_id" = "author"."id")
        ) AS "book_table"
      WHERE "rank" < %s ''', 10)

在上面的查询结果中,name字段有点模糊。我把这个对象传给另一个库,而那个库需要使用点符号,也就是说,q[0].name应该指的是书的名字,而q[0].author.name应该指的是作者的名字。请问在使用原始查询时,能不能用点符号?(最后的办法是用"author"."name" AS "author_name",但这样会引入多余的代码,因为那些函数也会从Django的管理查询中获取输入,而管理查询是支持点符号的。)

2 个回答

-2

我觉得你对在 models.manager 中的 raw 的意思有些困惑。

你可以使用 FooModel.objects.raw 来创建一个查询集(实际上是一个 RawQuerySet)用于 FooModel;传入 raw 的查询结果会被转换成 FooModel 对象。因此,你应该只返回与 FooModel 相关的字段。想要了解更多例子,可以查看这里的文档。我不太确定你提到的其他字段(比如作者的名字)会有什么效果,但我猜这会让 Django 感到困惑,可能无法达到你想要的效果。

如果你想执行完全自定义的命令并返回任意数据,你需要直接与数据库对话,像这里所示的那样。

不过在你的情况下,执行

q = Book.objects.raw('''
      SELECT "book"."id" FROM 
    ( SELECT "book"."id" 
             RANK() OVER (PARTITION BY "author"."id") AS "rank"
      FROM "book"
      INNER JOIN "book" ON ("book"."author_id" = "author"."id")
    ) AS "book_table"
  WHERE "rank" < %s ''', 10)
).prefetch_related("author")

应该能满足你的需求。这样会比你原来的原始查询多执行一次获取作者的查询,但为了避免直接处理底层数据库查询,这样做可能是可以接受的。

-2

最好尽量使用Django自带的查询语法,只手动添加排名字段。你可以用 extra 这个方法,而不是 raw,同时使用 select_related 来处理关系。可以像这样做:

Book.objects.select_related('author').extra(
    select={'rank': 'RANK() OVER (PARTITION BY "author"."id")'},
    where=['"rank" < 10']
)

撰写回答