Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Get average of annotated fields in Django (postgres)

Consider the following models:

class Employee(models.Model):
    name = models.Charfield(max_length=100)

class Evaluation(models.Model):
    employee = models.ForeignKeyField(Employee, on_delete=models.CASCADE)
    question1 = models.PositiveIntegerField(default=0)
    question2 = models.PositiveIntegerField(default=0)

The idea is that an employee is reviewed, and we are recording a score for each question.

I can get the total score for an employee’s evaluation by doing:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

models.Evaluation.objects.annotate(score=F(question1) + F(question2))

which is fine, but I would really like to be able to get an employee’s average score across multiple evaluations directly from the employee model.

I started with:

score_subquery = models.Evaluation.objects.annotate(score=F(question1) + F(question2)).filter(employee_id=OuterRef('pk').values('score')  
models.Employee.objects.annotate(avg_score=Avg(Subquery(score_subquery)))

This works fine until there is more than one evaluation for an employee, in which case we get:

more than one row returned by a subquery used as an expression

So I did some digging and came upon ArraySubquery

However, unfortunately this:

score_subquery = models.Evaluation.objects.annotate(score=F(question1) + F(question2)).filter(employee_id=OuterRef('pk').values('score')  
models.Employee.objects.annotate(avg_score=Avg(ArraySubquery(score_subquery)))

crashes with:

function avg(integer[]) does not exist

I assume that I have reached a postgres limitation?

I know I can get around this by using a real field to store the score, but I was just curious if this can be done strictly by using annotations?

>Solution :

You can work annotate with:

from django.db.models import Avg, F

models.Employee.objects.annotate(
    avg_score=Avg(F('evaluation__question1') + F('evaluation__question1'))
)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading