考虑简单的Django模型Event
和Participant
:
class Event(models.Model):
title = models.CharField(max_length=100)
class Participant(models.Model):
event = models.ForeignKey(Event, db_index=True)
is_paid = models.BooleanField(default=False, db_index=True)
很容易用参与者总数注释事件查询:
events = Event.objects.all().annotate(participants=models.Count('participant'))
如何使用按is_paid=True
筛选的参与者计数进行批注?
我需要查询所有事件,而不考虑参与者的数量,例如,我不需要根据带注释的结果进行筛选。如果有0
参与者,没关系,我只需要0
注释值。
这里的example from documentation不起作用,因为它从查询中排除对象,而不是用0
注释对象。
更新。Django 1.8有了新的conditional expressions feature,所以现在我们可以这样做:
events = Event.objects.all().annotate(paid_participants=models.Sum(
models.Case(
models.When(participant__is_paid=True, then=1),
default=0,
output_field=models.IntegerField()
)))
更新2。Django 2.0具有新的Conditional aggregation功能,请参见下面的the accepted answer。
刚刚发现Django 1.8有新的conditional expressions feature,所以现在我们可以这样做:
Django 2.0中的Conditional aggregation允许您进一步减少过去的faff数量。这也将使用Postgres'
filter
逻辑,这比求和的情况要快一些(我已经看到20-30%这样的数字出现在周围)。不管怎样,在你的情况下,我们正在寻找一些简单的东西:
文档中有一个关于filtering on annotations的单独部分。这和条件聚合是一样的,但更像我上面的例子。不管是哪种方式,这都比我以前做的那些烦人的子查询要健康得多。
更新
我提到的子查询方法现在在Django 1.11中通过subquery-expressions支持。
比起聚合(sum+case),我更喜欢这种方法,因为它应该更快、更容易优化(使用适当的索引)。
对于旧版本,也可以使用^{} 来实现
相关问题 更多 >
编程相关推荐