0

非常に厄介なサイクリングモデルの参照によって引き起こされた元の問題:

# A -> B -> A

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

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

ここで、クエリに注釈を付けようとすると、常に a.id の代わりに LEFT OUTER JOIN の GROUP BY a の id (以下の例では T3.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 の検索を停止しません。そのため、a.id ではなく T3.id によってグループ化が行われます (したがって、結果が欠落しています)。この問題を解決するには、 for ループ内にブレークポイントが必要です (コメントでマークされています)。

UPD: Django 1.8.2 バージョンで既に修正されている問題https://code.djangoproject.com/ticket/24748

于 2015-06-25T17:31:35.647 に答える