Django原始查询 - 使用点表示法遍历相关模型字段
这是我在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']
)