0

原来很尴尬的单车模型参考引起的问题:

# 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将排除结果,其中 ab == None

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

4

1 回答 1

0

打开 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 循环内需要断点(在注释中标记)。

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

于 2015-06-25T17:31:35.647 回答