带注释条件表达式的Django查询使用INNER JOIN.如何让它使用OUTER JOIN ?



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

我在Django 1.8中使用条件表达式,它总是将"Food"one_answers"Meal"之间的关系切换为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"
我知道这个问题与这个非常相似,但我不清楚如何将公认的解决方案应用到我的情况中。如何让Django使用LEFT OUTER JOIN?谢谢你的帮助!

我已经找到了一个解决方案,似乎是工作到目前为止,使用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)
            )
        )

相关内容

  • 没有找到相关文章

最新更新