Django query left join, sum and group by
У меня есть модель:
class Product(models.Model):
name = models.CharField(max_length=100)
class Sales(models.Model):
product_id = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='products')
date = models.DateTimeField(null=True)
price = models.FloatField()
Как вернуть данные в виде следующего sql-запроса (аннотировать продажи с названием продукта, сгруппировать по продукту, дню и месяцу и вычислить сумму продаж):
select p.name
, extract(day from date) as day
, extract(month from date) as month
, sum(s.price)
from timetracker.main_sales s
left join timetracker.main_product p on p.id = s.product_id_id
group by month, day, p.name;
Спасибо, Если бы только ORM был так же прост, как sql... Потратил несколько часов, пытаясь разобраться в этом...
PS. Почему при выполнении Sales.objects.raw(sql) с sql запросом выше я получаю "Raw query must include the primary key"
Вы можете аннотировать с помощью:
from django.db.models import Sum
from django.db.models.functions import ExtractDay, ExtractMonth
Product.objects.values(
'name',
month=ExtractDay('products__date')
day=ExtractDay('products__date'),
).annotate(
total_price=Sum('products__price')
).order_by('name', 'month', 'day')
Примечание: Обычно не добавляют суффикс
.…_id
к полюForeignKey
, так как Django автоматически добавит поле-"близнец" с суффиксом…_id
. Поэтому он должен бытьproduct
, вместо.product_id
Note: The
related_name=…
parameter [Django-doc] is the name of the relation in reverse, so from theProduct
model to theSales
model in this case. Therefore it (often) makes not much sense to name it the same as the forward relation. You thus might want to consider renaming therelation toproducts
sales
.