【问题标题】:Django 1.8 conditional annotation results in INNER JOIN instead of LEFT OUTER JOINDjango 1.8 条件注释导致 INNER JOIN 而不是 LEFT OUTER JOIN
【发布时间】:2015-07-28 17:39:28
【问题描述】:

模型:

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”总和注释,如果与“bar”相关的“foo”不存在,则为 0)而不是内部联接?是否可以不回退到原始 SQL?

【问题讨论】:

  • 作为未来人们的便条。这可能是由 1.8.3 中修复的错误引起的

标签: django django-models django-queryset django-orm django-1.8


【解决方案1】:

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

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()
                                 )
                            ),
                )

【讨论】:

    【解决方案2】:

    这是一个known bug,在 Django 1.8.3 (release notes) 中更正。

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

    使用高于 1.8.3 的 Django 版本将解决此问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-25
      • 2016-10-31
      • 2015-01-10
      • 1970-01-01
      • 2013-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多