I have the following two models.
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')
and
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)
I need to list all products with stock_in_sum=Sum(of all stock ins)
, stock_out_sum=Sum(of all stock outs)
and blance_stock=opening_stock+stock_in_sum - stock_out_sum
This is what I've achieved so far.
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'))
I need to get
stock_in_sum
as the sum(quantity) where ttype='I'
stock_out_sum
as the sum(quantity) where ttype='O'
blance_stock
as product.opening_stock + stock_in_sum - stock_out_sum
along with each Product object.
How do I achieve this?
Thanks.
Unlike aggregate() , annotate() is not a terminal clause. The output of the annotate() clause is a QuerySet ; this QuerySet can be modified using any other QuerySet operation, including filter() , order_by() , or even additional calls to annotate() .
The filter() method is used to filter you search, and allows you to return only the rows that matches the search term.
In the Django framework, both annotate and aggregate are responsible for identifying a given value set summary. Among these, annotate identifies the summary from each of the items in the queryset. Whereas in the case of aggregate, the summary is calculated for the entire queryset.
You could use 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)))
)
To make the sums, and after that compute the balance with F() expression
queryset = queryset.annotate(balance_stock=F('opening_stock') + F('stock_in_sum') - F('stock_out_sum'))
You can also chain the different operation instead of multiple assignations:
queryset = queryset.prefetch_related(...).annotate(...).annotate(...)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With