web-dev-qa-db-fra.com

Django Aggregate: Sum return value only?

J'ai une liste de valeurs payées et je souhaite afficher le total payé. J'ai utilisé l'agrégation et la somme pour calculer les valeurs ensemble. Le problème est que je veux juste que la valeur totale soit imprimée, mais l'aggrégation affiche: {'amount__sum': 480.0} (480,0 étant la valeur ajoutée totale.

À mon avis, j'ai:

    from Django.db.models import Sum

    total_paid = Payment.objects.all.aggregate(Sum('amount'))

Et pour afficher la valeur sur la page, j'ai un modèle mako avec ce qui suit:

    <p><strong>Total Paid:</strong> ${total_paid}</p>

Comment pourrais-je le faire montrer 480.0 au lieu de {'amount__sum': 480.0}?

26
Stephen

Je ne crois pas qu'il existe un moyen d'obtenir uniquement la valeur.

Vous pouvez simplement faire ${{ total_paid.amount__sum }} Dans votre modèle. Ou faites total_paid = Payment.objects.all().aggregate(Sum('amount')).get('amount__sum', 0.00) dans votre vue.

MODIFIER

Comme d'autres l'ont souligné, .aggregate() renverra toujours un dictionnaire avec toutes les clés des agrégats présents, donc .get() sur le résultat n'est pas nécessaire. Cependant, si l'ensemble de requêtes est vide, chaque valeur agrégée serait None. Donc selon votre code, si vous attendez un flottant, vous pouvez faire:

total_paid = Payment.objects.all().aggregate(Sum('amount'))['amount__sum'] or 0.00

32
jproffitt

Donnez-lui un nom puis demandez-le:

total_paid = Payment.objects.all.aggregate(sum=Sum('amount'))['sum']

Devrait être un peu plus lisible et aucune conversion n'est nécessaire.

17
mehmet

La méthode aggregate() renvoie un dictionnaire. Si vous savez que vous ne renvoyez qu'un dictionnaire à entrée unique, vous pouvez utiliser .values()[0].

Dans Python 2:

total_paid = Payment.objects.aggregate(Sum('amount')).values()[0]

Dans Python, (merci @lmiguelvargasf), cela devra être:

total_paid = list(Payment.objects.aggregate(Sum('amount')).values())[0]

Le résultat final est le même que la réponse de @ jproffitt, mais il évite de répéter le amount__sum part, c'est donc un peu plus générique.

17
nimasmi

Dans Python:

Vous pouvez le résoudre en convertissant le dict_values vers un list:

total_paid = list(Payment.objects.aggregate(Sum('amount')).values())[0] or 0 # the or 0 is required in case the query is an empty query set.

Le code précédent évite d'utiliser 'column_name__sum' comme clé, mais si vous préférez la méthode du dictionnaire:

total_paid = Payment.objects.aggregate(Sum('amount'))['amount__sum'] or 0

En termes d'efficacité, j'ai fait un test avec certaines données dont je dispose, et il semble que l'utilisation de la clé du dictionnaire soit plus rapide:

In [9]: %timeit total = Pledge.objects.filter(user=user, group__isnull=True).aggregate(Sum('amount'))['amount__sum'] or 0
3.13 ms ± 25.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [10]: %timeit total = list(Pledge.objects.filter(user=user, group__isnull=True).aggregate(Sum('amount')).values())[0] or 0
3.22 ms ± 61.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

En termes de lisibilité, je pense que la solution de @ mehmet est la meilleure, et j'ai également testé son efficacité:

In [18]: %timeit Pledge.objects.filter(user=user, group__isnull=True).aggregate(sum=Sum('amount'))['sum'] or 0
3.22 ms ± 124 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
1
lmiguelvargasf