【问题标题】:Django query with annotated conditional expression uses INNER JOIN. How do I get it to use OUTER JOIN?带注释条件表达式的 Django 查询使用 INNER JOIN。如何让它使用 OUTER JOIN?
【发布时间】:2015-08-06 00:27:41
【问题描述】:

我有一个带有“食物”外键的“膳食”模型。每顿饭都有一个等级:好、坏或无所谓。我想查询所有食物的列表并注释每种膳食评级的计数,但有些食物还没有膳食,所以我希望查询使用 LEFT OUTER JOIN,在这种情况下计数应该为零。

我在 Django 1.8 中使用条件表达式,它总是将关系切换到“食物”和“膳食”之间的 INNER JOIN。例如:

膳食模型:

class Meal(models.Model):
    GOOD = 1
    BAD = 2
    INDIFFERENT = 3
    RATING_CHOICES = (
        (GOOD, 'Good'),
        (BAD, 'Bad'),
        (INDIFFERENT, 'Indifferent')
    )
    meal_time = models.DateTimeField()
    food = models.ForeignKey("Food")
    rating = models.IntegerField(blank=True, null=True, choices=RATING_CHOICES)

当我查询Food.objects.annotate(total_meals=Count('meal')) 时,Django 会生成类似的查询

SELECT ... FROM "Food" 
LEFT OUTER JOIN "Meal" ON ... 
GROUP BY "Food"

但是,当我添加这些条件注释时:

class FoodQuerySet(models.QuerySet):
    def with_meal_rating_frequency(self):
        return self.annotate(
            total_meals=Count('meal'),
            good_meals=Sum(
                 Case(When(meal__rating=Meal.GOOD, then=1),
                    output_field=models.IntegerField(), default=0)
            ),
            bad_meals=Sum(
                Case(When(meal__rating=Meal.BAD, then=1),
                    output_field=models.IntegerField(), default=0)
            ),
            indifferent_meals=Sum(
                Case(When(meal__rating=Meal.INDIFFERENT, then=1),
                    output_field=models.IntegerField(), default=0)
            )
        )

Django 使用 and INNER JOIN

SELECT ... FROM "Food"
INNER JOIN "Meal" ON ...
GROUP BY "Food"

我知道这个问题与this one 非常相似,但我不清楚如何将接受的解决方案应用于我的案例。如何让 Django 使用 LEFT OUTER JOIN?感谢您的帮助,谢谢!

【问题讨论】:

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


    【解决方案1】:

    到目前为止,我找到了一个似乎可行的解决方案,使用 Count() 而不是 Sum() 并检查 NULL 餐食的条件,这不会包含在计数中:

    class FoodQuerySet(models.QuerySet):
        def with_meal_rating_frequency(self):
            return self.annotate(
                total_meals=Count('meal'),
                good_meals=Count(
                    Case(When(Q(meal__isnull=True) | Q(meal__rating=Meal.GOOD), then='meal__rating'),
                        output_field=models.IntegerField(), default=None)
                ),
                bad_meals=Count(
                    Case(When(Q(meal__isnull=True) | Q(meal__rating=Meal.BAD), then='meal__rating'),
                        output_field=models.IntegerField(), default=None)
                ),
                indifferent_meals=Count(
                    Case(When(Q(meal__isnull=True) | Q(meal__rating=Meal.INDIFFERENT), then='meal__rating'),
                        output_field=models.IntegerField(), default=None)
                )
            )
    

    【讨论】:

      猜你喜欢
      • 2015-07-28
      • 2015-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-01
      • 2012-11-04
      相关资源
      最近更新 更多