Django - 按组注释加权 AVG

Django - Annotating Weighted AVG by Group

我有以下在 SalesRecord 上运行的模型管理器:

def by_variety_and_date(self, start_date, end_date):
    return self.model.objects.filter(
        date__range=(start_date, end_date)
    ).values(
        "variety"
    ).annotate(
        qty_applied=Sum('qty_applied'),
        margin=Avg('margin')
    )

我真正想要的是 margin=Avg('margin') 到 return 的 加权 平均值,基于 qty_applied。有没有办法用 Django 的 annotate/aggregate 查询来做到这一点?我一直在尝试将 .aggregate() 串接到此结束,但我仍然想要这个查询集所描述的每个 variety 的平均值。

本例中的模型如下所示:

class Sale(models.Model):
    margin = models.DecimalField(null=True, blank=True, decimal_places=2, max_digits=12)
    qty_applied = models.IntegerField(null=True, blank=True)
    variety = models.ForeignKey(Variety, null=True)
    totals = Totals()

编辑

这就是我最终得到的结果。这有点靠不住,但它确实有效。

def by_variety_and_date(self, start_date, end_date):
    return self.model.objects.filter(
        date__range=(start_date, end_date)
    ).values(
        "variety"
    ).annotate(
        qty_applied=Sum('qty_applied'),
        profit=Sum('profit'),
        cogs=Sum('cogs'),
        sales=Sum('value'),
        margin=Sum(
            (F('qty_applied')*F('margin')), output_field=FloatField()
        ) / Sum(
            'qty_applied', output_field=FloatField())
    )

我使用了 F 个对象,因为 @WTower 建议将每个对象的 margin 乘以它的 qty_applied,然后将整个对象包裹在 Sum 中并除以组中所有对象的 qty_appliedSum。奇迹般有效!

您可以使用 F() expression

>>> from django.db.models import F, FloatField, Sum
>>> MyModel.objects.all().aggregate(
...    w_avg=Sum((F('a')*F('b'))/F('b'), output_field=FloatField()))

关于聚合的更多信息 here

或者,您可以使用自定义 SQL( 推荐)或管理器中的自定义方法。