我有一个"用餐"带有外键的模型" Food"。每顿饭都有评价:好,坏,或无动于衷。我想查询所有食物的列表并注释每种类型的膳食评级的数量,但是一些食物还没有进餐,所以我希望查询使用LEFT OUTER JOIN,在这种情况下,计数应该为零。
我在Django 1.8中使用条件表达式,它总是将关系切换为" Food"之间的内部联接。和"用餐"。例如:
膳食模型:
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使用和INNER JOIN
代替。
SELECT ... FROM "Food"
INNER JOIN "Meal" ON ...
GROUP BY "Food"
我知道这个问题与this one非常相似,但我不清楚如何将公认的解决方案应用于我的案例。如何让Django使用LEFT OUTER JOIN?感谢您的帮助,谢谢!
答案 0 :(得分: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)
)
)