4

I'm trying to aggregate a list of integers from a model. The field that the integers are derived from are an @property decorator field. The decorator works as expected and within the template.html, if passed directly, displays without a problem. If however, I try and pass the @property field through .aggregate() the context passed into the template throws an error that basically says Cannot resolve keyword 'sum_thing' into field. followed by a list of model fields that don't include any of the decorator fields.

My question is - how do you aggregate (Sum) derived fields from the model?

#models.py

class Foo(models.Model):
    a = 10      # a & b are both
    b = 5       # models.IntegerField() items

    @property
    def sum_thing(self):
        return self.a - self.b

#views.py

class Bar(generic.ListView):

    def get_context_data(self, **kwargs):

        qs = Foo.object.all()

        totals = {}

        totals['sumthing'] = qs.aggregate(total=Sum('sum_thing')

        context = {
            'totals': totals
        }

        return context

** I've greatly simplified the models.py and the views.py.

Bill Armstrong
  • 1,443
  • 3
  • 18
  • 41

1 Answers1

12

You can not aggregate using properties since it does not exist in the db. But, you can annotate your query with the help of Django's F expressions to get the actual value for those fields. See the example below.

from django.db.models import F, Sum

Foo.objects.annotate(sum_a_and_b=F('a') + F('b')).aggregate(total=Sum('sum_a_and_b'))

Also you can do any mathematical operation like / * + - with F, also you can do like this

.annotate(answer=F('a') + F('b') * 2)
Andrey Berenda
  • 1,772
  • 2
  • 12
  • 22
  • For my clarification - `.annotate()` is basically recomputing the `@property` function. Then the `.aggregate()` method does the 'Sum' for the annotation. In other words, if there is no need to call directly the result of the decorator these calculations can all be done in the formation of the context return. Thanks again. – Bill Armstrong May 15 '18 at 04:03
  • if you do annotate, after this you can call it too. If you do annotate the database calculate your result and if you do @property python calculate result.Only it is defference – Andrey Berenda May 15 '18 at 04:07
  • Thanks, it very helpfull – pije76 Sep 29 '20 at 19:27