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 the Product model to the Sales 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 the products relation to sales.

Вернуться на верх