2017-05-19 1 views
2

J'ai les deux QuerySets annotés suivants que j'ai générés séparément en extrayant this_wk et prev_wk d'un ensemble de données, puis en effectuant l'annotation. Je voudrais les fusionner ensemble avant de les retourner.Comment puis-je filtrer par date pour obtenir cette semaine par rapport à la semaine précédente Compte à partir d'un QuerySet?

data = { 
    'this_wk': QuerySet([{'this_total': 3, 'dept': 2}, 
         {'this_total': 2, 'dept': 1}, 
         {'this_total': 1, 'dept': 3}]), 
    'prev_wk': QuerySet([{'prev_total': 2, 'dept': 3}])} 

à prévoir:

QuerySet([{'this_total': 3, 'prev_total': None, 'dept': 2}, 
      {'this_total': 2, 'prev_total': None, 'dept': 1}, 
      {'this_total': 1, 'prev_total': 2, 'dept': 3}]), 

Sinon, est-il un moyen d'agréger ce directement pour que je vais directement à partir d'un ensemble d'éléments avec des champs de date? Voilà comment je génère actuellement les deux QuerySets:

previous_items = Widget.objects.filter(start__gte=prev_start).filter(start__lte=prev_end) 
prev_ranking = previous_items.values('dept').annotate(prev_total=Count('dept')) 

this_items = Widget.objects.filter(start__gte=this_start 
    ).filter(start__lte=this_end) 
this_ranking = this_items.values('dept' 
    ).annotate(this_total=Count('dept') 
    ).order_by('-this_total') 

Est-il possible d'enchaîner ces deux annotations ensemble pour que je me retrouve avec un seul QuerySet groupés et un classement pour chaque Dept selon le nombre Widgets il a été utilisé par cette semaine, mais aussi avec un champ ajouté qui indique combien de Widgets il a été utilisé par la semaine précédente?

Je pense quelque chose comme ceci:

items = Widget.objects.filter(start__gte=prev_start 
    ).filter(start__lte=this_end 
    ).annotate(prev_total=Count('dept') # can I restrict this to the previous week? 
    ).annotate(this_total=Count('dept') # can I restrict this to the current week? 
    ).order_by('-this_total') 

Répondre

1

Qu'est-ce que vous pensez semble correct pour votre cas. Afin d'obtenir ce que vous avez besoin, vous pouvez appliquer les éléments suivants:

  1. Petit mais utile est la range recherche qui vous permet de filtrer entre deux valeurs
  2. Pour limiter vos annotate arguments, vous devez utiliser conditional aggregation.

En fin de votre requête ressemblera à ceci:

items = Widget.objects.filter(start__range=(prev_start, this_end)) 
         .values('dept') 
         .annotate(
          prev_total=Count(
           Case(
            When(start__lte=prev_end, then=1)),     
            output_field=IntegerField())), 
          this_total=Count(
           Case(
            When(start__gte=this_start, then=1), 
            output_field=IntegerField()))) 
         .order_by('-this_total') 

EDIT EN RAISON DE COMMENTAIRE:

Cette étape est nécessaire dans ce cas, cela aiderait pour construire une annotation pour additionner les valeurs des champs dept filtrés.

  1. j'utiliser l'expression F() prendre la valeur de chaque champ dept dans l'annotation et Sum fonction au lieu de Count ajouter ces valeurs.
+0

Merci, c'est certainement le long des bonnes lignes. Il manque juste '.values ​​('dept')' avant le premier 'annotate' pour obtenir exactement ce que je cherche. Aussi, pourquoi utiliser l'expression 'F' et' Sum' plutôt que 'Count'? En raison de la condition de course mentionnée dans les documents liés? –

+1

@JamieBull J'étais sous l'hypothèse que vous deviez ajouter les valeurs 'dept' ensemble et avoir leur somme.Si ce n'est pas le cas et que vous avez juste besoin de compter le nombre de valeurs 'dept', alors je vais éditer la réponse :). En attendant, je vais éditer les valeurs ('dept') 'dans la réponse! –

+0

Oui, c'est juste de compter combien de valeurs de rayon il y a, donc je n'ai pas besoin du 'F'? –