Агрегирование Django / Python по месяцам и кварталам - PullRequest
2 голосов
/ 01 февраля 2011

Я пишу функцию, которая требует средней цены товара в разное время (неделя, месяц, квартал и т. Д.). Вот модель:

class ItemPrice(models.Model):
    item = models.ForeignKey(Item)
    date = models.DateField()
    price = models.FloatField()

Эта модель отслеживает цену товара с течением времени, и новые товары добавляются с частыми, но не регулярными интервалами. Найти среднее значение price за последнюю неделю достаточно просто:

ItemPrice.objects.filter(item__id = 1)
    .filter(date_lt = TODAY)
    .filter(date_gte = TODAY_MINUS_7_DAYS)
    .filter(date_.aggregate(Avg('value'))

Как неделя всегда имеет 7 дней, но как насчет месяца и квартала? У них разное количество дней ...?

Спасибо!

EDIT: Приложение предназначено для финансовой организации, боюсь, 30-дневные месяцы, спасибо за предложение!

Ответы [ 4 ]

2 голосов
/ 07 октября 2014
import datetime
from dateutil import relativedelta, rrule  

obj = self.get_object()  
datenow = datetime.datetime.now() 

quarters = rrule.rrule(
        rrule.MONTHLY,
        bymonth=(1, 4, 7, 10),
        bysetpos=-1,
        dtstart=datetime.datetime(datenow.year, 1, 1),
        count=5)

    first_day = quarters.before(datenow)
    last_day = (quarters.after(datenow) - relativedelta.relativedelta(days=1))

    quarter = Payment.objects.filter(
        operation__department__cashbox__id=obj.pk,
        created__range=(first_day, last_day)).aggregate(count=Sum('amount'))

вдохновение оттуда

2 голосов
/ 08 февраля 2011

Решение состоит из двух частей: первая использует агрегацию функций django ORM, вторая использует python-dateutil .

from dateutil.relativedelta import relativedelta

A_MONTH = relativedelta(months=1)

month = ItemPrice.objects \
    .filter(date__gte = date - A_MONTH) \
    .filter(date__lt = date) \
    .aggregate(month_average = Avg('price'))

month равно:

{'month_average': 40}

Стоит заметить, что вы можете изменить ключ словаря month, изменив параметр .aggregate().

Относительная

dateutil может обрабатывать дни, недели, годы и многое другое. Отличный пакет, я переписываю свой доморощенный хак.

1 голос
/ 01 февраля 2011

Прежде всего, вас интересуют последние 7 дней или последняя неделя? Если ответ на прошлой неделе, ваш запрос неверен.

Если вас беспокоит «n» дней, значит ваш запрос верный, и я полагаю, вы можете просто расслабиться и использовать 30 дней в течение месяца и 90 дней в течение квартала.

1 голос
/ 01 февраля 2011

Я бы пошел за 360-дневным календарем и не беспокоился об этих маленьких неточностях.Просто используйте последние 30 дней для своего "среднего значения за последний месяц" и последние 90 дней для своего "среднего значения за последний квартал".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...