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,615
  • 3
  • 23
  • 47

2 Answers2

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)
Andrei Berenda
  • 1,946
  • 2
  • 13
  • 27
  • 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 – Andrei Berenda May 15 '18 at 04:07
  • Thanks, it very helpfull – panjianom Sep 29 '20 at 19:27
1

the true way is using annotate as Andrey said, anyway when using complex properties than can not be calculated in annotate, you can use django-queryable-properties

hadi ahadi
  • 116
  • 1
  • 1
  • 6
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/32373780) – Simas Joneliunas Aug 05 '22 at 01:12