Django ORM how to Round an Avg result

前端 未结 5 1574
礼貌的吻别
礼貌的吻别 2020-12-10 12:59

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 pri

相关标签:
5条回答
  • 2020-12-10 13:36

    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))
    
    0 讨论(0)
  • 2020-12-10 13:36

    Django has the Round function. For more detail please see the documentation

    0 讨论(0)
  • 2020-12-10 13:47

    Improving on @mrts answer.

    This allows the round function to be parameterised:

    class Round(Func):
      function = 'ROUND'
      arity = 2
    
    Book.objects.all().aggregate(Round(Avg('price'), 2))
    
    0 讨论(0)
  • 2020-12-10 13:51

    I needed to have both PostgreSQL and SQLite support, but also keep the ability to specify the number of digit to keep.

    Build on previous answers :

    class Round(Func):
        function = 'ROUND'
        arity = 2
        # Only works as the arity is 2
        arg_joiner = '::numeric, '
    
        def as_sqlite(self, compiler, connection, **extra_context):
            return super().as_sqlite(compiler, connection, arg_joiner=", ", **extra_context)
    
    # Then one can use it as:
    # queryset.annotate(avg_val=Round(AVG("val"), 6))
    

    I would have prefered something cleaner like

    if SQLITE:
        arg_joiner=", "
    elif PGSQL:
        arg_joiner = '::numeric, '
    else raise NotImplemented()
    

    but did not find how, feel free to improve !

    0 讨论(0)
  • 2020-12-10 13:54

    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
    
    0 讨论(0)
提交回复
热议问题