【问题标题】:django - annotate() - Sum() of a column with filter on another columndjango - annotate() - 列的 Sum() 与另一列上的过滤器
【发布时间】:2018-01-12 09:33:08
【问题描述】:

我有以下两种型号。

class Product(models.Model):
    product_group=models.ForeignKey('productgroup.ProductGroup', null=False,blank=False)
    manufacturer=models.ForeignKey(Manufacturer, null=False,blank=False)
    opening_stock=models.PositiveIntegerField(default=0)

    class Meta:
        unique_together = ('product_group', 'manufacturer')

TRANSACTION_TYPE=(('I','Stock In'),('O','Stock Out'))
class Stock(models.Model):
    product=models.ForeignKey('product.Product', blank=False,null=False)
    date=models.DateField(blank=False, null=False,)
    quantity=models.PositiveIntegerField(blank=False, null=False)
    ttype=models.CharField(max_length=1,verbose_name="Transaction type",choices=TRANSACTION_TYPE, blank=False)

我需要列出所有带有 stock_in_sum=Sum(of all stock ins)stock_out_sum=Sum(of all stock outs)blance_stock=opening_stock+stock_in_sum - stock_out_sum 的产品

这是我目前所取得的成就。

class ProductList(ListView):
    model=Product

    def get_queryset(self):
        queryset = super(ProductList, self).get_queryset()
        queryset = queryset.prefetch_related('product_group','product_group__category','manufacturer')
        queryset = queryset.annotate(stock_in_sum = Sum('stock__quantity'))
        queryset = queryset.annotate(stock_out_sum = Sum('stock__quantity'))

我需要得到

  1. stock_in_sum 作为sum(quantity) where ttype='I'
  2. stock_out_sum 作为sum(quantity) where ttype='O'
  3. blance_stockproduct.opening_stock + stock_in_sum - stock_out_sum

连同每个 Product 对象。

我如何做到这一点?

谢谢。

【问题讨论】:

    标签: django listview django-annotate


    【解决方案1】:

    你可以使用conditional aggregation

    queryset = queryset.annotate(
        stock_in_sum = Sum(Case(When(stock__ttype='I', then=F('stock__quantity')), output_field=DecimalField(), default=0)),
        stock_out_sum = Sum(Case(When(stock__ttype='O', then=F('stock__quantity')), output_field=DecimalField(), default=0)))
    )
    

    求和,然后用F() expression计算余额

    queryset = queryset.annotate(balance_stock=F('opening_stock') + F('stock_in_sum') - F('stock_out_sum'))
    

    您还可以链接不同的操作而不是多个分配:

    queryset = queryset.prefetch_related(...).annotate(...).annotate(...)
    

    【讨论】:

    • 谢谢!它要求我使用 ExpressionWrapper()。得到前两个数据如下queryset = queryset.annotate( stock_in_sum = Sum(Case(When(stock__ttype='I', then= ExpressionWrapper(F('stock__quantity'), output_field=DecimalField())))) ) queryset = queryset.annotate( stock_out_sum = Sum(Case(When(stock__ttype='O', then= ExpressionWrapper(F('stock__quantity'), output_field=DecimalField())))) )
    • queryset = queryset.annotate( balance_stock = ExpressionWrapper(F('opening_stock') + F('stock_in_sum') - F('stock_out_sum'), output_field=DecimalField()) ) 为所有行提供无stock_in_sumstock_out_sum 为无。
    • 看起来我需要在某处返回 0 而不是 None,但不知道如何。
    • 我编辑了答案以添加默认值,因此它不会尝试添加 None,而是添加 0。
    • 太棒了!这给出了我想要的确切结果。不再有重复的查询:)
    猜你喜欢
    • 2021-01-30
    • 1970-01-01
    • 2020-10-11
    • 2021-01-26
    • 2021-12-01
    • 2021-12-27
    • 1970-01-01
    • 2022-11-26
    • 2011-08-11
    相关资源
    最近更新 更多