Агрегация Джанго по диапазону дат

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

у меня есть следующие модели:

Asset(Model)

BookedAsset(Model):
 asset = models.ForeignKey(Asset)
 startdate = models.DateField()
 enddate = models.DateField()

Таким образом, имея следующие записи:

asset 1, 2010-02-11, 2010-02-13
asset 2, 2010-03-12, 2010-03-14
asset 1, 2010-04-30, 2010-05-01

Я хотел бы получить следующее:

asset 1    asset 2
-------    -------
Jan = 0    Jan = 0
Feb = 2    Feb = 0
Mar = 0    Mar = 2
Apr = 1    Apr = 0
May = 1    May = 0
Jun = 0    Jun = 0
Jul = 0    Jul = 0
Aug = 0    Aug = 0
Sep = 0    Sep = 0
Oct = 0    Oct = 0
Nov = 0    Nov = 0
Dec = 0    Dec = 0

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

Любая помощь (или подсказка в правильном направлении) очень ценится.

4 ответа

Решение

В конце я выбрал собственный запрос в качестве решения моего вопроса:

cursor = connection.cursor()
cursor.execute("""select to_char(allmonths.yeardate::date, 'YYYY/MM/DD') as monthdate,
                    COUNT("day") as bookings
                    from (
                    select distinct date_trunc('month', (date %s - offs)) as yeardate 
                    from generate_series(0,365,28) as offs
                    ) as allmonths
                    left join bookings_bookedassetday 
                    on EXTRACT(MONTH from "day")=EXTRACT(MONTH from yeardate) 
                    and asset_id=%s and EXTRACT(YEAR from "day") = %s
                    group by allmonths.yeardate
                    order by allmonths.yeardate asc""", [year+'-12-31', id, year])

query = cursor.fetchall()

Возможно, это не самый лучший способ сделать это, но я нашел это гораздо проще, чем понять это с помощью чистого django:|

Если у кого-то есть лучшая альтернатива, я весь в ушах:)

Я не могу придумать способ сделать это с вашей моделью.

Это довольно сложное требование, и как бы вы его ни решали, вероятно, потребуется много пользовательского SQL. Я думаю, что для начала вам может понадобиться изменить свою структуру, чтобы BookedAssetDay таблица, которая представляет каждый день отдельно для бронирования.

class BookedAsset(models.Model):
    asset = models.ForeignKey(Asset)
    day = models.DateField()

Тогда запрос выглядит примерно так:

BookedAsset.objects.extra(
    select={'month': 'MONTH(day)'}
).values('asset', 'month').annotate(Count('bookedasset__month'))

Есть другое решение, которое делает это через представление базы данных и отображает это представление в модель django, используя опцию мета-класса managed = False

Подробные объяснения здесь: http://anthony-tresontani.github.com/Django/2012/09/12/wka-django-orm-limitations/

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

Ответ, который вы ищете, - это функция annotate() в функции агрегирования django: http://docs.djangoproject.com/en/dev/topics/db/aggregation/ Единственное, что вам нужно знать, это как месяц для даты, который объясняется в документации набора запросов: http://docs.djangoproject.com/en/dev/ref/models/querysets/

Грубый пример, чтобы получить его для одного актива:

BookedAsset.objects.filter(asset=asset).annotate(month_count=Count('startdate__month')).order_by('startdate__month')

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

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

Другие вопросы по тегам