multiple statistics on django

2

I have to calculate a series of data for my project, it works 100% when it comes to general calculation, but when I try to take those same calculations to the facilities ( jovenclubs ) separately it returns me a list with all the values it contains:

example: joven club x has a field called Natural , with a series of data, which I want to add.

This is the view of the general values , it works fine:

def inicio(request):
    plan_gral = jovenclub.objects.aggregate(sum=Sum('plan_gral'))
    juridic_gral = ingresos.objects.aggregate(sum=Sum('juridico'))
    natural_gral = ingresos.objects.aggregate(sum=Sum('natural'))
    general = juridic_gral['sum']+natural_gral['sum']
    diferencia = plan_gral['sum']-general
    porciento_general = general*100/plan_gral['sum']

    ingreso = ingresos.objects.all()

    mes = datetime.now().month
    meses=ingresos.objects.filter(fecha__month = mes)
    year = datetime.now().year
    amo=ingresos.objects.filter(fecha__year = year)

and this is the view of the installations :

def detalle_jc(request, id_jovenclub ):
    jc = jovenclub.objects.get(pk=id_jovenclub)
    datos=ingresos.objects.all()
    print jc.ingresos_set.all()
    sum=0
    for ingreso in jc.ingresos_set.all():
        sum=ingreso.get_importe()
    sum=(round((sum/jc.plan_gral)*100,2))

This is the call in the template :

{% for ingreso in jc.ingresos_set.all %}
{{ ingreso.natural }}
{% endfor %}

Return the following:

  

3974.0 5200.0 4875.0

These are the data in the field Natural , which should add

model.py:

class jovenclub(models.Model):
    nombre = models.CharField(max_length=15, choices=JOVENCLUB)
    especialista = models.CharField(max_length=50)
    plan_gral = models.FloatField()
    def __unicode__(self):
        return self.nombre

class ingresos(models.Model):
    # mes = models.IntegerField(validators=[no_negativo])
    jovenclub = models.ForeignKey(jovenclub)
    natural = models.FloatField(blank=True)
    juridico = models.FloatField(blank=True)
    fecha = models.DateField()
    def get_importe(self):
      return self.natural+self.juridico
    importe = property(get_importe)
    
asked by Roly Miranda Díaz 21.04.2017 в 19:23
source

1 answer

5

We are going to do a Minimum, complete and verifiable example for which, we are going to use this mini model, which has All the information we need:

from django.db import models

class Ingresos(models.Model):
    club = models.PositiveSmallIntegerField()
    natural = natural = models.FloatField(blank=True)

    def __str__(self):
      return '%s' % self.club
  

See how the code is correctly colored when you use the format button correctly: {} .

Now let's use some test data:

id | club | natural
1  |   1  |   5.0
2  |   1  |   5.0
3  |   1  |   5.0
4  |   2  |   3.0
5  |   2  |   3.0
6  |   2  |   3.0
7  |   3  |   2.0
8  |   3  |   2.0
9  |   3  |   2.0
10 |   3  |   2.0

There are three club records 1 , all with a value in natural of 5 . there are 3 club records 2 , with a natural of 3 and there are 4 club records 3 with an associated value of natural equal to 2. The totals would be 15 for club 1, 9 for club 2 and 8 for club 3. The grand total is 15 + 9 + 8 = 32. That's what we want to find.

We will use the aggregate method to apply the Sum function to all records.

In [3]: Ingresos.objects.all().aggregate(Sum('natural'))
Out[3]: {'natural__sum': 32.0}

The result is 32.0 , which is the expected result.

We can improve our query a bit more by assigning a label to the result:

In [4]: Ingresos.objects.values('club').aggregate(total_general=Sum('natural'))
Out[4]: {'total_general': 32.0}

Now let's get the results grouped by club. For this, we will use the Annotate method, which, unlike the previous one, groups the results by object . In our example, we want to group the results by club .

We are simply going to add the indicated field to make the summary, in the following way:

In [5]: Ingresos.objects.values('club').annotate(Sum('natural'))
Out[5]: <QuerySet [{'club': 1, 'natural__sum': 15.0}, {'club': 2, 'natural__sum': 9.0}, {'club': 3, 'natural__sum': 8.0}]>

As you can see, this is the expected result. And in the same way, we can add a label to improve the presentation and control.

In [6]: Ingresos.objects.values('club').annotate(natural_por_club=Sum('natural'))
Out[6]: <QuerySet [{'club': 1, 'natural_por_club': 15.0}, {'club': 2, 'natural_por_club': 9.0}, {'club': 3, 'natural_por_club': 8.0}]>
  

Important

     

The grouping you do using the values method is different depending on where you do the summary and where you group the data. In the previous example, first group them and then summarize them, but see the following example:

 In [7]: Ingresos.objects.annotate(natural_por_club=Sum('natural')).values('club')
 Out[7]: <QuerySet [{'club': 1}, {'club': 1}, {'club': 1}, {'club': 2}, {'club': 2}, {'club': 2}, {'club': 3}, {'club': 3}, {'club': 3}, {'club': 3}]>

To conclude, you can add to the Annotate method the operations you need, separated by a comma and each of them can have its own label. And even more, you can bring related fields and group them, so a query like the following is perfectly valid.

jovenclub.objects.values('club').annotate(\
    total_plan_gra=Sum('plan_gral'),\
    total_juridico=Sum('juridico'),\
    total_natural=Sum('natural')
)

So it is possible that in a single statement you have all your aggregation operations.

  

Note

     

It is important to note that unlike Aggregate , the Annotate method returns a QuerySet , which means that it is not a final function and you can continue to apply filters and queries, as you normally do with any QuerySet.

    
answered by 21.04.2017 / 20:34
source