【问题标题】:Django raw query - use dot notation for traversing related model's fieldsDjango 原始查询 - 使用点符号遍历相关模型的字段
【发布时间】:2014-10-17 15:37:15
【问题描述】:

这是我在 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 托管查询的输入,支持点表示法)。

【问题讨论】:

    标签: python django django-queryset


    【解决方案1】:

    这样可能还是尽量使用Django自带的查询语法,只手动添加rank字段。您可以使用extra 而不是raw 来执行此操作,并使用select_related 来遍历关系。像这样的:

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

    【讨论】:

    • 我收到一个错误:ProgrammingError: column "rank" does not exist。我不需要嵌套选择来在 where 子句中使用 rank 吗? According to docs "窗口函数只允许在查询的SELECT列表和ORDER BY子句中使用。在其他地方禁止使用,例如在GROUP BY、HAVING和WHERE子句中......如果需要过滤或分组执行窗口计算后的行,您可以使用子选择" ... .extra() 可以吗?
    【解决方案2】:

    我认为您对rawmodels.manager 上下文中的含义感到困惑。

    您可以使用FooModel.objects.raw为FooModel创建一个查询集(实际上是一个RawQuerySet);传递给raw 的查询结果将被转换为 FooModels;因此,您应该只返回与 FooModel 相关的字段。有关示例,请参阅文档中的 here。不确定哪些附加字段(例如您示例中的 author.name)会做什么,但我的猜测是它会使 Django 感到困惑,并且不会按照您的意愿去做。

    如果你想运行返回任意数据的完全任意命令,你需要像here那样直接与数据库对话。

    在你的情况下,做

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

    应该做你想做的。与原始原始查询相比,它会多执行一次查询来获取作者,但这可能是可以接受的,以换取不必处理裸机数据库查询。

    【讨论】:

    • 理论上,您的示例听起来可能可行,但 Django 不支持它。我得到一个错误:RawQuerySet 对象没有属性prefetch_related。其次,不确定您如何得出结论:you should only return fields pertaining to FooModel。我已经能够加入复杂的模型并使用原始查询管理器返回它们的字段并且它们工作正常。
    • 好的,那么 RawQuerySet 相当有限,不支持简单数据访问之外的任何内容。我怀疑原始查询实际上是否会使用模型中超出的任何字段,因此当它工作时,它可能只是重新获取相关对象。
    猜你喜欢
    • 2011-03-10
    • 2020-07-31
    • 2021-11-14
    • 2016-04-02
    • 1970-01-01
    • 2015-08-31
    • 1970-01-01
    • 2021-09-03
    • 1970-01-01
    相关资源
    最近更新 更多