开发者

Django aggregation on a date range

I have been lurking and learning in here for a while. Now i have a problem that somehow i cannot see an easy solution. In order 开发者_StackOverflow社区to learn django i am bulding an app that basically keeps track of booked items. What I would like to do is to show how many days per month for a selected year one item has been booked.

i have the following models:

Asset(Model)

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

So having the following entries:

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

I would like to get returned the following:

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

I know i need to first get the number of days in a date range (and keep track if they fall out of the current month and into the next month) and then do an agregate on the number of days. I am just stuck on how to do it elegantly in Django.

Any help (or hint in the right direction) is greatly appreciated.


I can't think of a way of doing it with the model structure you have.

This is a fairly complex requirement, and however you solve it is probably going to require quite a lot of custom SQL. I think as a start though you might need to consider changing your structure so that you have a BookedAssetDay table, which represents each day separately for a booking.

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

Then the query looks something like:

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


I wouldn't go for either answer above (even do I like punching out some custom SQL but I haven't done that in at least 5 years) and your model is simple enough to be workable in a relational paradigm.

The answer you're looking for is is the annotate() function in django's aggregation functionality: http://docs.djangoproject.com/en/dev/topics/db/aggregation/ Only thing you need to know is how to get at the month for the date, which is explained in the queryset documentation: http://docs.djangoproject.com/en/dev/ref/models/querysets/#month

A rough example to get it for one asset:

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

(obviously wrong, but I couldn't be arsed to recreate your structure to give you the exact correct statement, fiddle around a bit and read the documentation)

You could probably even though it in one go for all assets by using the join syntax in the same docs.


At the end I went with a custom query as a solution to my question:

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()

Maybe it is not the most django-ist way of doing it but I found it way easier than figuring it out with pure django :|

If somebody else has a better alternative I am all ears :)


There is another solution which is doing it through a database view and mapping that view to a django model using the meta class option managed = False

Detailed explanations here: http://anthony-tresontani.github.com/Django/2012/09/12/wka-django-orm-limitations/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜