Сумма агрегированных значений в Django

Я пытаюсь выполнить следующий SQL-запрос в Django:

(Таблица содержит данные о покупках за каждый день для каждого места. Я хочу получить наибольшее количество покупок в каждом месте, затем сгруппировать их по штатам, чтобы увидеть, сколько максимально можно продать в каждом штате)

select state, type, sum(amount)
    from (
        select l.state, dd.type, max(amount) as amount 
        from daily_data dd
        join locations l on l.id = dd.location_id
        where dd.type in ('purchases', 'returns')
        group by dd.location_id, dd.type
    )
    group by state, type

Где я получаю вот это:

NY,purchases,80
NY, returns,6
Maine,purchases,125
Maine, returns,12

Но я застрял на том, как добиться этого в django.

Я попробовал следующее:

daily_data.objects.filter(type__in=['purchases', 'returns']
        ).values('location', 'type'
        ).annotate(total=Max('amount')
        ).values('location__state','type'
        ).annotate(sum=Sum('total'))

Но я получаю ошибку django.core.exceptions.FieldError: Cannot compute Sum('total'): 'total' is an aggregate

Я даже пробовал использовать подзапрос, но он генерирует плохой sql-запрос, в результате чего запрос выполняется бесконечно долго.

subquery = daily_data.objects.filter(
    location=OuterRef('location'),
    type=OuterRef('type')
).values('location', 'type').annotate(
    max_amount=Max('amount')
).values('max_amount')

annotated_data = daily_data.objects.filter(
    type__in=['purchases', 'returns']
).annotate(
    max_amount=Subquery(subquery)
).values(
    'location__state', 'type'
).annotate(
    total_max_amount=Sum('max_amount')
).order_by('location__state', 'type')

Это генерирует:

SELECT "state", "type", SUM((
        SELECT MAX(U0."amount") AS "total" FROM "daily_data" U0
        INNER JOIN "locations" U1 ON (U0."location_id" = U1."id")
        WHERE (U1."state" = ("state") AND U2."type" = "type") GROUP BY U0."location_id", U2."type")) AS "total"
FROM "daily_data"
    INNER JOIN "locations" ON ("location_id" = "locations"."id") WHERE where "type" in ('purchases', 'returns')
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             GROUP BY "state", "type"

что избыточно и дорого... И я не успел увидеть результат, так как он загружается вечно...

Привет, я не эксперт в django orm, но для меня, когда программное создание запроса становится сложным при использовании django или spring (java framework), я часто просто предпочитаю писать sql напрямую, и django предоставляет вам такую возможность

django raw sql

где вы можете просто

     result=daily_data.objects.raw(
        """
            select state, type, sum(amount)
            from (
                select l.state, dd.type, max(amount) as amount 
                from daily_data dd
                join locations l on l.id = dd.location_id
                where dd.type in ('purchases', 'returns')
                group by dd.location_id, dd.type
            )
            group by state, type
        """
    )

    for value in result.iterator():
        print(value)

и использовать итератор для просмотра значений, хотя это всего лишь предложение, надеюсь, оно поможет :)

примечание: пожалуйста, обязательно следуйте документации при использовании метода raw для предотвращения sql-инъекций.

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