Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django ORM how to Round an Avg result

I have a model in which I use Django ORM to extract Avg of values from the table. I want to Round that Avg value, how do I do this?

See below I am extracting Avg price from Prices model grouped by date in format YYYY-MM, I want to automatically extract the average values rounded to the closest number.

rs = Prices.objects.all.extra(select={
    'for_date': 'CONCAT(CONCAT(extract( YEAR from for_date ), "-"),
        LPAD(extract(MONTH from for_date), 2, "00"))'
    }).values('for_date').annotate(price=Avg('price')).order_by('-for_date')
like image 445
Ami Avatar asked Dec 10 '12 01:12

Ami


2 Answers

Use Func() expressions.

Here's an example using the Book model from Django Aggregation topic guide to round to two decimal places in SQLite:

class Round(Func):
    function = 'ROUND'
    template='%(function)s(%(expressions)s, 2)'

Book.objects.all().aggregate(Round(Avg('price')))

This allows the round function to be parameterised (from @RichardZschech's answer):

class Round(Func):
  function = 'ROUND'
  arity = 2

Book.objects.all().aggregate(Round(Avg('price'), 2))
like image 84
mrts Avatar answered Oct 09 '22 20:10

mrts


Building on previous answers, I've come to this solution to make it work for PostgreSQL:

from django.db.models import Func

class Round2(Func):
    function = "ROUND"
    template = "%(function)s(%(expressions)s::numeric, 2)"

# Then use it as ,e.g.:
# queryset.annotate(ag_roi=Round2("roi"))

# qs.aggregate(ag_sold_pct=Round2(Sum("sold_uts") / (1.0 * Sum("total_uts"))) * 100
like image 33
msonsona Avatar answered Oct 09 '22 19:10

msonsona