【问题标题】:Wrong GROUP BY field in Django annotate queryDjango注释查询中错误的GROUP BY字段
【发布时间】:2015-09-12 02:21:17
【问题描述】:

原来很别扭的单车模型参考引起的问题:

# A -> B -> A

class A:
    b = models.ForeignKey('B', null=True, blank=True)

class B:
    a = models.ForeignKey('A')

现在,当我尝试注释查询时,它总是使用 GROUP BY a 的 LEFT OUTER JOIN 的 id(在下面的示例中为 T3.id)而不是 a.id。

例子:

A.objects.select_related('b', 'b__a').annotate(reviews=Count('reviews'))

生成的 SQL:

SELECT 
    `a`.`id`,
    `b`.`id`,
    T3.`id`,
FROM
    `a`
        LEFT OUTER JOIN
    `b` ON (`a`.`b_id` = `b`.`id`)
        LEFT OUTER JOIN
    `a` T3 ON (`b`.`a_id` = T3.`id`)
WHERE
    `a`.`id` IN (1, 2, 3, 4, 5)
GROUP BY T3.`id`
ORDER BY NULL;

我知道我可以做接下来的事情:

  1. 更改模型不做自行车参考(很遗憾现在不能这样做)
  2. 可以使用 .extra() 代替注释(我会尽量避免)
  3. 移除 .select_related() 调用(由于性能问题无法执行)

UPD:使用 GROUP BY T3.id 将排除结果,其中 a.b == None

对我来说最好的解决方案是在 GROUP BY 子句中指定正确的字段,但我不知道如何。可能吗?有没有其他方法可以解决这个问题?谢谢。

【问题讨论】:

  • 不是T3==a,来自a as T3吗?不知道你想在这里实现什么..
  • 使用 GROUP BY T3.id 排除了 a.b == None 的结果,同时它不是预期的。
  • 至于我试图实现的目标 - 模型可以通过 B 拥有父对象。我知道这不是最好的方法,但它是一种模型进化。

标签: sql django django-models django-orm django-aggregation


【解决方案1】:

打开的 Django 编译器:

def collapse_group_by(self, expressions, having):
    # If the DB can group by primary key, then group by the primary key of
    # query's main model. Note that for PostgreSQL the GROUP BY clause must
    # include the primary key of every table, but for MySQL it is enough to
    # have the main table's primary key. Currently only the MySQL form is
    # implemented.
    # MySQLism: however, columns in HAVING clause must be added to the
    # GROUP BY.
    if self.connection.features.allows_group_by_pk:
        # The logic here is: if the main model's primary key is in the
        # query, then set new_expressions to that field. If that happens,
        # then also add having expressions to group by.
        pk = None
        for expr in expressions:
            if (expr.output_field.primary_key and
                    getattr(expr.output_field, 'model') == self.query.model):
                pk = expr
                # HERE BREAKPOINT REQUIRED
        if pk:
            expressions = [pk] + [expr for expr in expressions if expr in having]
    return expressions

因此,collapse_group_by 函数即使已经找到 pk 也不会停止寻找,这就是为什么分组是由 T3.id 而不是 a.id 完成的(因此我丢失了结果)。 为了解决这个问题,for循环内部需要断点(用cmets标记)。

UPD:该问题已在 Django 1.8.2 版本 https://code.djangoproject.com/ticket/24748 中修复

【讨论】:

    猜你喜欢
    • 2021-06-05
    • 2019-06-09
    • 2016-03-20
    • 1970-01-01
    • 2017-08-17
    • 2021-10-23
    • 2017-12-23
    • 2021-08-10
    • 2020-07-09
    相关资源
    最近更新 更多