Django 1.8 条件注释导致 INNER JOIN 而不是 LEFT OUTER JOIN

Django 1.8 conditional annotation results in INNER JOIN instead of LEFT OUTER JOIN

模特:

class Bar(GenericModel):
    ...

class Foo(GenericModel):
    bar = models.ForeignKey(Bar, related_name='foo_bar')

查询:

bars = Bar.objects
       .prefetch_related('foo_bar')
       .annotate(sum_foo=Sum(
                             Case(
                                  When(foo_bar__is_deleted=False, then='foo_bar__amount'),
                                  default=Value(0),
                                  output_field=IntegerField()
                                 )
                            )
                )

前者导致内部联接:SELECT ... FROM "bar" INNER JOIN "foo" ON ( "bar"."id" = "foo"."bar_id" ) ...

我打算获得的是一个 LEFT OUTER JOIN("bar" 个对象的完整列表,用 "foo.amount" 和注释,如果 "foo" 与 "bar" 相关则为 0不存在)而不是 INNER JOIN?是否可以不退回到原始 SQL?

这种方式似乎可以正常工作:

bars = Bar.objects
       .prefetch_related('foo_bar')
       .annotate(sum_foo=Sum(
                             Case(
                                  When(Q(foo_bar__is_deleted=False) | Q(foo_bar__is_deleted=None),
                                                 then='foo_bar__amount'),
                                  default=Value(0),
                                  output_field=IntegerField()
                                 )
                            ),
                )

这是一个 known bug, corrected in Django 1.8.3 (release notes).

如您所述,问题是正在创建 INNER JOIN,在与 Foo 个对象没有对应关系时过滤掉 Bar 个对象。

使用1.8.3以上的Django版本即可解决问题。