2010-05-23 14 views
2

Je me suis caché et j'ai appris ici pendant un moment. Maintenant, j'ai un problème que d'une manière ou d'une autre je ne peux pas voir une solution facile. Afin d'apprendre le django, je suis en train de construire une application qui conserve la trace des articles réservés. Ce que je voudrais faire, c'est montrer combien de jours par mois pour une année sélectionnée un article a été réservé.Agrégation Django sur une plage de dates

j'ai les modèles suivants:

Asset(Model) 

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

Ainsi, ayant les entrées suivantes:

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

Je voudrais obtenir retourné les éléments suivants:

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 

Je sais que je dois d'abord obtenir le nombre de jours dans une plage de dates (et garder la trace si elles tombent hors du mois en cours et dans le e le mois prochain), puis faire une agrégation sur le nombre de jours. Je suis juste coincé sur la façon de le faire avec élégance dans Django.

Toute aide (ou indice dans la bonne direction) est grandement appréciée.

Répondre

0

A la fin je suis allé avec une requête personnalisée en tant que solution à ma 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() 

Peut-être que ce n'est pas le plus django-ist façon de le faire, mais je l'ai trouvé beaucoup plus facile que de le comprendre avec pur django: |

Si quelqu'un d'autre a une meilleure alternative que je suis toutes les oreilles :)

+0

Vous devriez accepter cette réponse, afin que la communauté puisse dire en un coup d'œil que vous n'avez pas besoin d'aide supplémentaire. –

0

Je ne peux pas penser à une façon de le faire avec la structure du modèle que vous avez.

Ceci est une exigence assez complexe, et cependant vous aurez besoin de beaucoup de SQL personnalisé. Je pense que pour commencer, vous devrez peut-être envisager de modifier votre structure afin d'avoir une table BookedAssetDay, ce qui représente chaque jour séparément pour une réservation.

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

Ensuite, la requête ressemble à quelque chose comme:

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

A la fin, je pense que je ira avec votre solution en ajoutant une table supplémentaire. La seule chose à faire est que plusieurs utilisateurs ont de nombreux atouts, donc la table BookedAssetDay peut grossir ... – klaut

+0

Ou je pourrais aussi utiliser la solution à cette réponse: http://stackoverflow.com/questions/1371280/query-for -values-based-on-date-w-django-orm de toute façon, j'apprécie votre réponse, Daniel! :) – klaut

0

Je ne voudrais pas aller soit pour répondre ci-dessus (même ce que j'aime poinçonnage une SQL personnalisée mais je ne l'ai pas fait dans au moins 5 ans) et votre modèle est assez simple pour être réalisable dans un paradigme relationnel.

La réponse que vous cherchez est est la annoter() dans la fonctionnalité d'agrégation de django: http://docs.djangoproject.com/en/dev/topics/db/aggregation/ La seule chose que vous devez savoir est comment obtenir au mois de la date, ce qui est expliqué dans la documentation queryset : http://docs.djangoproject.com/en/dev/ref/models/querysets/#month

un exemple difficile à obtenir pour un actif:

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

(évidemment faux, mais je ne pouvais pas être arsed pour recréer votre structure pour vous donner la déclaration exacte correcte, violon autour d'un peu et lire la documentation)

Vous pourriez probablement même en une seule fois pour tous les actifs en utilisant la syntaxe de jointure dans les mêmes docs.