Как сделать aggregate raw sql с юлианской датой в sqlite (с помощью django)

Я использую sqlite3 и django. Я хочу вычислить среднее значение для всех дней между last_played и now. (Last_played - это просто поле времени даты).

У меня на данный момент:

    avg_days_last_played_sql = """
        AVG(julianday('now') - julianday(played_at))
    """

    # Annotate the average days last played
    average_days_last_played = Song.objects.aggregate(
        avg_days_last_played=RawSQL(avg_days_last_played_sql, [])
    )['avg_days_last_played']

Но он выдает ошибку:

TypeError: avg_days_last_played не является агрегированным выражением

Я не думаю, что для этого нужен собственный сырой запрос. Мы можем работать с:

from django.db.models import FloatField
from django.db.models.expressions import Func


class JulianDay(Func):
    function = 'julianday'
    output_field = FloatField()

и затем работайте с:

from django.db.models import Avg, F
from django.db.models.functions import Now

Song.objects.aggregate(
    avg_days_last_played=Avg(JulianDay(Now()) - JulianDay(F('played_at')))
)['avg_days_last_played']

Теперь мы можем использовать функцию JulianDay во всех других выражениях, тем самым не только решив эту проблему, но и сделав более удобным решение смежных задач.

При этом хранение played_at в песне выглядит странно, обычно вы создаете отдельную модель, которая хранит для каждой песни, когда она была проиграна, чтобы вы могли выполнять дополнительную фильтрацию, агрегирование и т.д.

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