2010-03-09 4 views
0

J'ai un modèle de rapport à la recherche un peu comme ceci:Comment obtenir les valeurs des dernières entrées regroupées par attributs à l'aide de Django ORM?

class Report(models.Model): 
    date = models.DateField() 
    quantity = models.IntegerField() 
    product_name = models.TextField() 

Je sais que je peux obtenir la dernière entrée pour l'année dernière pour un produit de cette façon:

Report.objects.filter(date__year=2009, product_name="corn").order_by("-date")[0] 

Je sais que je peux groupe entrées par nom de cette façon:

Report.objects.values("product_name") 

Mais comment puis-je obtenir la quantité pour la dernière entrée pour chaque produit? Je me sens comme je le ferais de cette façon dans SQL (pas sûr, mon SQL est rouillé):

SELECT product_name, quantity FROM report WHERE YEAR(date) == 2009 GROUP_BY product_name HAVING date == Max(date) 

Je suppose d'utiliser l'objet Max() avec annoter, mais je ne sais pas comment.

Pour l'instant, je le fais en ajoutant manuellement le dernier élément de chaque requête pour chaque nom de produit que je ne peux pas lister avec un distinct.

Répondre

2

Pas exactement une requête triviale utilisant soit le ORM Django ou SQL. Ma première prise de vue serait à peu près ce que vous faites probablement déjà; obtenir les paires de produits et de dates distinctes, puis effectuer des requêtes individuelles pour chacun d'entre eux.

year_products = Product.objects.filter(year=2009) 
product_date_pairs = year_products.values('product').distinct('product' 
     ).annotate(Max('date')) 
[Report.objects.get(product=p['product'], date=p['date__max']) 
     for p in product_date_pairs] 

Mais vous pouvez prendre un peu plus loin avec l'opérateur Q et certains OR'ing de fantaisie pour couper votre requête compte à rebours à 2 au lieu de N + 1.

import operator 
qs = [Q(product=p['product'], date=p['date__max']) for p in product_date_pairs] 
ored_qs = reduce(operator.or_, qs) 
Report.objects.filter(ored_qs) 
+0

+1 Bien sûr, s'il y a beaucoup de produit, il peut s'agir d'une seconde requête looooooooooooooog. Peut-être que je m'en tiendrai à la première solution à moins que je rencontre des problèmes de performance. Il serait intéressant de savoir si le second est vraiment plus rapide, vu que le db sera sqlite. –

+0

Très vrai, les choses pourraient devenir folles. Essayez les deux et comparez les performances. Si vous évaluez les performances dans le shell, jetez un oeil à django.db.connection.queries. – istruble

Questions connexes