Django:使用前缀和注释模型
Django: Annotate model with a prefix sum
我有一个模型 TimeTrial
,它聚合了 Leg
的有序列表。
class TimeTrial(models.Model):
objects = TimeTrialManager()
class Leg(models.Model):
timetrial = models.ForeignKey(TimeTrial)
duration = models.FloatField()
order = models.PositiveIntegerField(default=0)
@property
def duration_prefix_sum(self):
qs = Leg.objects.filter(timetrial=self.timetrial,
order__lte=self.order)
return qs.aggregate(Sum('duration'))
class TimeTrialManager(models.Manager):
def get_queryset(self):
qs = super(TimeTrialManager, self).get_queryset()
qs = qs.annotate(leg_count=Count('leg'))
qs = qs.annotate(duration=Sum('leg__duration'))
return qs
(the actual models 的精简版。)
TimeTrialManager
用Leg
的个数和Leg.duration
的总和注释每个TimeTrial
。我想以类似的方式使用 Django 的 annotate
/aggregate
来计算 duration_prefix_sum
,所以当我在 timetrial.leg_set.all()
.
我知道我可以编写 Python 代码来计算它:
timetrial.leg_set_annotated = []
s = 0
for l in timetrial.leg_set.all():
s += l.duration
l.duration_prefix_sum_computed = s
timetrial.leg_set_annotated.append(l)
但我更愿意使用 Django 的 annotate/aggregate/Case/When。
我找到了解决方案,但我不确定它是否完全可靠。我 implemented it in my project.
我们添加过滤器 timetrial__leg__order__lte=F('order')
以添加包含订单小于或等于当前的所有边的连接。
然后,我们添加注释 duration_prefix_sum
作为 Sum('timetrial__leg__duration')
,计算前缀和。
from django.db.models import Sum, F
qs = Leg.objects.filter(timetrial__leg__order__lte=F('order'))
qs = qs.annotate(duration_prefix_sum=Sum('timetrial__leg__duration'))
我认为如果使用此查询集的代码在 'timetrial__leg'
上创建另一个 annotation/filter,这将失败,因此欢迎添加以使其更健壮。
我有一个模型 TimeTrial
,它聚合了 Leg
的有序列表。
class TimeTrial(models.Model):
objects = TimeTrialManager()
class Leg(models.Model):
timetrial = models.ForeignKey(TimeTrial)
duration = models.FloatField()
order = models.PositiveIntegerField(default=0)
@property
def duration_prefix_sum(self):
qs = Leg.objects.filter(timetrial=self.timetrial,
order__lte=self.order)
return qs.aggregate(Sum('duration'))
class TimeTrialManager(models.Manager):
def get_queryset(self):
qs = super(TimeTrialManager, self).get_queryset()
qs = qs.annotate(leg_count=Count('leg'))
qs = qs.annotate(duration=Sum('leg__duration'))
return qs
(the actual models 的精简版。)
TimeTrialManager
用Leg
的个数和Leg.duration
的总和注释每个TimeTrial
。我想以类似的方式使用 Django 的 annotate
/aggregate
来计算 duration_prefix_sum
,所以当我在 timetrial.leg_set.all()
.
我知道我可以编写 Python 代码来计算它:
timetrial.leg_set_annotated = []
s = 0
for l in timetrial.leg_set.all():
s += l.duration
l.duration_prefix_sum_computed = s
timetrial.leg_set_annotated.append(l)
但我更愿意使用 Django 的 annotate/aggregate/Case/When。
我找到了解决方案,但我不确定它是否完全可靠。我 implemented it in my project.
我们添加过滤器 timetrial__leg__order__lte=F('order')
以添加包含订单小于或等于当前的所有边的连接。
然后,我们添加注释 duration_prefix_sum
作为 Sum('timetrial__leg__duration')
,计算前缀和。
from django.db.models import Sum, F
qs = Leg.objects.filter(timetrial__leg__order__lte=F('order'))
qs = qs.annotate(duration_prefix_sum=Sum('timetrial__leg__duration'))
我认为如果使用此查询集的代码在 'timetrial__leg'
上创建另一个 annotation/filter,这将失败,因此欢迎添加以使其更健壮。