django queryset aggregate multiple operations fields - django

model.py
class Fatture(models.Model):
numero = models.CharField(max_length=30, null=True, blank=True)
data = models.DateField()
iva = models.PositiveIntegerField()
commissione = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
class Ddts(models.Model):
fattura = models.ForeignKey('Fatture')
class DdtsArticoli(models.Model):
ddt = models.ForeignKey('Ddts')
articolo = models.ForeignKey('Articoli')
quantita = models.DecimalField(max_digits=6, decimal_places=2)
prezzo = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
colli = models.PositiveIntegerField()
I have to make a query that calculate this total:
aggregate table DdtsArticoli SUM(quantita * prezzo)
aggregate table DdtsArticoli ((quantita * prezzo) / (1 + (iva of table
Fatture)/100 ))
resut of 1) - result of 2)

See the Django docs on aggregation for detail but 1. should be something like:
from django.db.models import Sum
DdtsArticoli.objects.all().aggregate(
your_key=Sum(F('quantita') * F('prezzo'), output_field=FloatField()))
Number 2. is no aggragation, you can simply calculate it:
(obj.quantita * obj.prezzo) / (1 + (obj.ddt.fattura.iva/100.0))
Where obj is your object aka. your database row.
Number 3. should be trivial then.

Related

Join two models and group with SUM in Django

I have two model name ProductDetails and InventorySummary. I want to join this two model and wants to group with product name and SUM product quantity. The quantity should be multiplication with product price. My models are given bellow:
class ProductDetails(models.Model):
id = models.AutoField(primary_key=True)
product_name = models.CharField(max_length=100, unique=True)
purchase_price = models.DecimalField(max_digits=7, decimal_places=2)
dealer_price = models.DecimalField(max_digits=7, decimal_places=2)
retail_price = models.DecimalField(max_digits=7, decimal_places=2)
remarks = models.CharField(max_length=255, blank=True)
def __str__(self):
return self.product_name
class InventorySummary(models.Model):
id = models.AutoField(primary_key=True)
date = models.DateField(default=date.today)
product_name = models.ForeignKey(ProductDetails, on_delete=models.CASCADE)
quantity = models.IntegerField()
def __str__(self):
return str(self.product_name)
My views are given bellow:
def stockPrice(request):
stock = InventorySummary.objects.select_related('product_name').
values('product_name').annotate(quantity=Sum('quantity'))
return render(request, 'inventory_price.html', {'stock': stock})
I can achieve this with the F expression. I'm not sure what you refer to by "product price", so I took purchase_price:
from django.db.models import Sum, F
stock = (
InventorySummary.objects.values("product_name__product_name")
.order_by("product_name__product_name")
.annotate(quantity=Sum(F("product_name__purchase_price") * F("quantity")))
)

Django Filter specific user's salary within giving date range

I have Two models :
class MonthSalary(models.Model):
month = models.DateField(null=True)
def __str__(self):
return str(self.month.year) + '/' + str(self.month.month)
class SalaryPerMonth(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
salary_month = models.ForeignKey(MonthSalary, null=True, on_delete=models.CASCADE)
main_salary_per_month = models.PositiveIntegerField(default=0, null=True)
net_salary_per_month = models.PositiveIntegerField(default=0, null=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=["user", "salary_month"], name="all_keys_unique_together")]
def __str__(self):
return str(self.user.employeedetail.empcode) + ' ' + str(self.net_salary_per_month) + ' USD' + str(
self.salary_month)
In Views I can query all user salaries with :
user = request.user
salary_per_month = SalaryPerMonth.objects.filter(user=user)
In MonthSalary model I added a bunch of months\years not in order Ex "2022-2,2022-4,2022-1,2021-4" when I filter user's salary by ordering the date "related salary_month field" like so :
salary_per_month = SalaryPerMonth.objects.filter(user=user).order_by('salary_month')
It's not in order.
Q1 = How how filter by Year ?
Q2 = How to order by month ?
So this is the answer to part one of my question "Q2" ordering by Month
All I did is add Meta class:
class Meta:
class MonthSalary(models.Model):
month = models.DateField(null=True)
class Meta:
ordering = ['-month']
class SalaryPerMonth(models.Model):
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
salary_month = models.ForeignKey(MonthSalary, null=True, on_delete=models.CASCADE)
main_salary_per_month = models.PositiveIntegerField(default=0, null=True)
net_salary_per_month = models.PositiveIntegerField(default=0, null=True)
class Meta:
ordering = ['-salary_month']

F expression conjunction with Sum() is not working as expected

class Order(models.Model):
pass
class OrderItems(models.Model):
order = models.ForiegnKey(Order, related_name="items")
name = models.CharField(max_length=255, null=False)
quantity = models.DecimalField(max_digits=5, decimal_places=2)
supplier = models.CharField(max_length=255, null=False)
purchase_price = models.DecimalField(max_digits=10, decimal_places=2)
trade_price = models.DecimalField(max_digits=10, decimal_places=2,blank=False, null=False , default = 0.00)
retail_price = models.DecimalField(max_digits=10, decimal_places=2)
class OrderItemSalesTax(models.Model):
order_item = models.ForiegnKey(OrderItems, related_name="sales_tax")
name = models.CharField(max_length=255)
percentage = models.DecimalField(max_digits=6, decimal_places=2)
class OrderItemDiscount(models.Model):
order_item = models.OneToOneField(OrderItem, primary_key=True, on_delete=models.CASCADE, related_name='discount')
name = models.CharField(max_length=255)
discount = models.DecimalField(max_digits=6, decimal_places=2)
in_percentage = models.BooleanField()
I am using this query to calculate the total amount, but also deducting discount and adding Sales tax.
Sum(F('items__sales_tax__percentage')) value is 25, and I have verified it, querying the database. Right now I have only One order and two Items and Items have two Sales Taxes and One Discount
I am trying to Sum the Sales taxes to apply on discounted price, but I am getting the wrong result results. If I manually write 25 by replacing Sum(F('items__sales_tax__percentage')) then results are correct, is there anything wrong with my query ?
Order.objects.filter(customer__zone__distribution=get_user_distribution(request.user.id))\
.annotate(
trade_price=Sum(F('items__trade_price') * F('items__quantity')),
tax = Sum(F('items__sales_tax__percentage')),
discounted_price = F('trade_price') * ExpressionWrapper(0.01 * (100 - Sum(F('items__discount__discount'))), output_field=DecimalField()),
total = F('discounted_price') + F('discounted_price') * Sum(F('items__sales_tax__percentage')) / 100
)

How to query pass 2 of multiple conditions

I need query objects passed 2 of multiple conditions. Example:
We have a model:
class A(models.Model):
id = models.PositiveSmallIntegerField(primary_key=True)
cost = models.IntegerField(null=True, blank=True)
price = models.IntegerField(null=True, blank=True)
quality = models.IntegerField(null=True, blank=True)
code = models.CharField(max_length=255, null=True, blank=True)
name = models.CharField(max_length=255, null=True, blank=True)
address = models.CharField(max_length=255, null=True, blank=True)
Conditions:
cost < 5
price < 7
quality > 0
...
code = 1234
name contains 'apple'
Result can be:
- 'C' item with cost = 6, price = 6, quality = 2, code = 321, name = 'asd asdsd'
- 'D' with value: cost=4, price=6, quality=2, code=322, name='xyz'
How to query item passed as less 2 conditions?
We can first annotate with the number of conditions that are satified, and then filter on that number:
from django.db.models import Q, IntegerField
from django.db.models.functions import Cast
A.objects.annotate(
nvalid=Cast(Q(cost__lt=5), output_field=IntegerField()) +
Cast(Q(price__lt=7), output_field=IntegerField()) +
Cast(Q(quality__gt=0), output_field=IntegerField()) +
Cast(Q(code='1234'), output_field=IntegerField()) +
Cast(Q(name__contains='apple'), output_field=IntegerField())
).filter(nvalid__gte=2)

how to sum all the consummations?

I already calculate, the total of one consummation, now i just want to sum all the consumations
class Consommation(models.Model):
food = models.ManyToManyField(Food)
consomme_le = models.DateTimeField(default=timezone.now, editable=False)
vipcustomer = models.ForeignKey(VipCustomer, models.CASCADE, null=True,
blank=True, verbose_name='Client prestigieux',
related_name='vip_consommations')
to calculate one consummation:
def total(self):
return self.food.aggregate(total=Sum('price'))['total']
Food class :
class Food(models.Model):
nom = models.CharField(max_length=100, verbose_name='Mon menu')
price = models.PositiveIntegerField(verbose_name='Prix')
category = models.ForeignKey(FoodCategory, models.CASCADE,
verbose_name="Categorie")
vipcustomer class:
class VipCustomer(models.Model):
first_name = models.CharField(max_length=150, verbose_name='Prénom')
last_name = models.CharField(max_length=100, verbose_name='Nom')
matricule = models.PositiveIntegerField(verbose_name='Matricule',
default=0)
adresse = models.CharField(max_length=200, verbose_name='Adresse',
blank=True)
telephone = PhoneField()
company = models.CharField(max_length=100, verbose_name='La société')
service = models.CharField(max_length=100, verbose_name='Service',
null=True, blank=True)
numero_badge = models.IntegerField(verbose_name='Numero du badge',
null=True, blank=True)
My goal is to calculate the total of all the consummations.
For a given VipCustomers, you can query with:
my_vip_customer.vip_consommations.aggregate(
total=Sum('food__price')
)['total']
We thus aggregate over the set of related Consommations, and we then aggregate over all the related Foods of these Consommations, and their corresponding price.
If there are no related Consommations, or no related Foods of these Consommations, then the sum will return None, instead of 0. We can add or 0 to convert a None to an 0 here:
my_vip_customer.vip_consommations.aggregate(
total=Sum('food__price')
)['total'] or 0
or for all Customers, we can annotate this with:
VipCustomer.objects.annotate(
total=Sum('vip_consommations__food__price')
)
Here the VipCustomers that arise from this, will have an extra attribute .total that contains the sum of the prices of the related Foods of the related Consommations.